HTTP_WebDAV_Client
[ class tree: HTTP_WebDAV_Client ] [ index: HTTP_WebDAV_Client ] [ all elements ]

Source for file Stream.php

Documentation is available at Stream.php

  1. <?php
  2. require "HTTP/Request.php";
  3. require "HTTP/WebDAV/Tools/_parse_propfind_response.php";
  4. require "HTTP/WebDAV/Tools/_parse_lock_response.php";
  5.  
  6. // WebDAV defines some addition HTTP methods
  7. define('HTTP_REQUEST_METHOD_COPY',      'COPY',      true);
  8. define('HTTP_REQUEST_METHOD_MOVE',      'MOVE',      true);
  9. define('HTTP_REQUEST_METHOD_MKCOL',     'MKCOL',     true);
  10. define('HTTP_REQUEST_METHOD_PROPFIND',  'PROPFIND',  true);
  11. define('HTTP_REQUEST_METHOD_PROPPATCH''PROPPATCH'true);
  12. define('HTTP_REQUEST_METHOD_LOCK',      'LOCK',      true);
  13. define('HTTP_REQUEST_METHOD_UNLOCK',    'UNLOCK',    true);
  14.  
  15. /**
  16.  * A stream wrapper class for WebDAV access
  17.  *
  18.  * @access public
  19.  */
  20. class HTTP_WebDAV_Client_Stream 
  21. {
  22.     /**
  23.      * The http or https resource URL
  24.      *
  25.      * @access private
  26.      * @var    string  url
  27.      */
  28.     var $url = false;
  29.  
  30.     /**
  31.      * The resource URL path
  32.      *
  33.      * @access private
  34.      * @var    string  path
  35.      */
  36.     var $path = false;
  37.  
  38.     /**
  39.      * File position indicator
  40.      *
  41.      * @access private
  42.      * @var    int     offset in bytes
  43.      */
  44.     var $position = 0;
  45.  
  46.     /**
  47.      * File status information cache
  48.      *
  49.      * @access private
  50.      * @var    array   stat information
  51.      */
  52.     var $stat = array();
  53.  
  54.     /**
  55.      * User name for authentication
  56.      *
  57.      * @access private
  58.      * @var    string  name
  59.      */
  60.     var $user = false;
  61.  
  62.     /**
  63.      * Password for authentication
  64.      *
  65.      * @access private
  66.      * @var    string  password
  67.      */
  68.     var $pass = false;
  69.  
  70.     /**
  71.      * WebDAV protocol levels supported by the server
  72.      *
  73.      * @access private
  74.      * @var    array   level entries
  75.      */
  76.     var $dav_level = array();
  77.  
  78.     /**
  79.      * HTTP methods supported by the server
  80.      *
  81.      * @access private
  82.      * @var    array   method entries
  83.      */
  84.     var $dav_allow = array();
  85.  
  86.     /**
  87.      * Directory content cache
  88.      *
  89.      * @access private
  90.      * @var    array   filename entries
  91.      */
  92.     var $dirfiles = false;
  93.  
  94.     /**
  95.      * Current readdir() position
  96.      *
  97.      * @access private
  98.      * @var    int 
  99.      */
  100.     var $dirpos = 0;
  101.  
  102.     /**
  103.      * Remember if end of file was reached
  104.      *
  105.      * @access private
  106.      * @var    bool 
  107.      */
  108.     var $eof = false;
  109.  
  110.     /**
  111.      * Lock token
  112.      *
  113.      * @access private
  114.      * @var    string 
  115.      */
  116.     var $locktoken = false;
  117.  
  118.     /**
  119.      * Stream wrapper interface open() method
  120.      *
  121.      * @access public
  122.      * @var    string resource URL
  123.      * @var    string mode flags
  124.      * @var    array  not used here
  125.      * @var    string return real path here if suitable
  126.      * @return bool   true on success
  127.      */
  128.     function stream_open($path$mode$options&$opened_path
  129.     {
  130.         // rewrite the request URL
  131.         if (!$this->_parse_url($path)) return false;
  132.  
  133.         // query server for WebDAV options
  134.         if (!$this->_check_options())  return false;
  135.  
  136.         // now get the file metadata
  137.         // we only need type, size, creation and modification date
  138.         $req &new HTTP_Request($this->url);
  139.         $req->setMethod(HTTP_REQUEST_METHOD_PROPFIND);
  140.         if (is_string($this->user)) {
  141.             $req->setBasicAuth($this->user@$this->pass);          
  142.         }
  143.         $req->addHeader("Depth""0");
  144.         $req->addHeader("Content-Type""text/xml");
  145.         $req->addRawPostData('<?xml version="1.0" encoding="utf-8"?>
  146. <propfind xmlns="DAV:">
  147.  <prop>
  148.   <resourcetype/>
  149.   <getcontentlength/>
  150.   <getlastmodified />
  151.   <creationdate/>
  152.  </prop>
  153. </propfind>
  154. ');
  155.         $req->sendRequest();
  156.  
  157.         // check the response code, anything but 207 indicates a problem
  158.         switch ($req->getResponseCode()) {
  159.         case 207: // OK
  160.             // now we have to parse the result to get the status info items
  161.             $propinfo &new HTTP_WebDAV_Client_parse_propfind_response($req->getResponseBody());
  162.             $this->stat $propinfo->stat();
  163.             unset($propinfo);
  164.             break;
  165.  
  166.         case 404: // not found is ok in write modes
  167.             if (preg_match('|[aw\+]|'$mode)) {
  168.                 break; // write
  169.             
  170.             $this->eof = true;
  171.             // else fallthru
  172.         default: 
  173.             error_log("file not found: ".$req->getResponseCode());
  174.             return false;
  175.         }
  176.         
  177.         // 'w' -> open for writing, truncate existing files
  178.         if (strpos($mode"w"!== false{
  179.             $req &new HTTP_Request($this->url);
  180.             $req->setMethod(HTTP_REQUEST_METHOD_PUT);
  181.             if (is_string($this->user)) {
  182.                 $req->setBasicAuth($this->user@$this->pass);          
  183.             }
  184.             $req->sendRequest();
  185.         }
  186.  
  187.         // 'a' -> open for appending
  188.         if (strpos($mode"a"!== false{
  189.             $this->eof = true;
  190.         }
  191.  
  192.         // we are done :)
  193.         return true;
  194.     }
  195.  
  196.  
  197.     /**
  198.      * Streap wrapper interface close() method
  199.      *
  200.      * @access public
  201.      */
  202.     function stream_close(
  203.     {
  204.         // unlock?
  205.         if ($this->locktoken{
  206.             $this->stream_lock(LOCK_UN);
  207.         }
  208.  
  209.         // closing is simple as HTTP is stateless 
  210.         $this->url = false;
  211.     }
  212.  
  213.     /**
  214.      * Stream wrapper interface stat() method
  215.      *
  216.      * @access public
  217.      * @return array  stat entries
  218.      */
  219.     function stream_stat(
  220.     {
  221.         // we already have collected the needed information 
  222.         // in stream_open() :)
  223.         return $this->stat;
  224.     }
  225.  
  226.     /**
  227.      * Stream wrapper interface read() method
  228.      *
  229.      * @access public
  230.      * @param  int    requested byte count
  231.      * @return string read data
  232.      */
  233.     function stream_read($count
  234.     {
  235.         // do some math
  236.         $start $this->position;
  237.         $end   $start $count - 1;
  238.  
  239.         // create a GET request with a range
  240.         $req &new HTTP_Request($this->url);
  241.         $req->setMethod(HTTP_REQUEST_METHOD_GET);
  242.         if (is_string($this->user)) {
  243.             $req->setBasicAuth($this->user@$this->pass);          
  244.         }
  245.         $req->addHeader("Range""bytes=$start-$end");
  246.  
  247.         // go! go! go!
  248.         $req->sendRequest();
  249.         $data $req->getResponseBody();
  250.         $len  strlen($data);
  251.  
  252.         // lets see what happened
  253.         switch ($req->getResponseCode()) {
  254.         case 200: 
  255.             // server doesn't support range requests 
  256.             // TODO we should add some sort of cacheing here
  257.             $data substr($data$start$count);
  258.             break;
  259.  
  260.         case 206:
  261.             // server supports range requests
  262.             break;
  263.  
  264.         case 416:
  265.             // reading beyond end of file is not an error
  266.             $data "";
  267.             $len  = 0;
  268.             break;
  269.  
  270.         default: 
  271.             return false;
  272.         }
  273.  
  274.         // no data indicates end of file
  275.         if (!$len{
  276.             $this->eof = true;
  277.         }
  278.  
  279.         // update position
  280.         $this->position += $len;
  281.  
  282.         // thats it!
  283.         return $data;
  284.     }
  285.  
  286.     /**
  287.      * Stream wrapper interface write() method
  288.      *
  289.      * @access public
  290.      * @param  string data to write
  291.      * @return int    number of bytes actually written
  292.      */
  293.     function stream_write($buffer
  294.     {
  295.         // do some math
  296.         $start $this->position;
  297.         $end   $this->position strlen($buffer);
  298.  
  299.         // create a partial PUT request
  300.         $req &new HTTP_Request($this->url);
  301.         $req->setMethod(HTTP_REQUEST_METHOD_PUT);
  302.         if (is_string($this->user)) {
  303.             $req->setBasicAuth($this->user@$this->pass);          
  304.         }
  305.         $req->addHeader("Content-Range""bytes $start-$end/*");
  306.         if ($this->locktoken{
  307.             $req->addHeader("If""(<{$this->locktoken}>)");
  308.         }
  309.         $req->addRawPostData($buffer);
  310.  
  311.         // go! go! go!
  312.         $req->sendRequest();
  313.  
  314.         // check result
  315.         switch ($req->getResponseCode()) {
  316.         case 200:
  317.         case 201:
  318.         case 204:
  319.             $this->position += strlen($buffer);
  320.             return $end $start;
  321.             
  322.         default: 
  323.             return false;
  324.         }
  325.  
  326.         /* 
  327.          We do not cope with servers that do not support partial PUTs!
  328.          And we do assume that a server does conform to the following 
  329.          rule from RFC 2616 Section 9.6:
  330.          "The recipient of the entity MUST NOT ignore any Content-* 
  331.          (e.g. Content-Range) headers that it does not understand or 
  332.          implement and MUST return a 501 (Not Implemented) response 
  333.          in such cases."
  334.            
  335.          So the worst case scenario with a compliant server not 
  336.          implementing partial PUTs should be a failed request. A 
  337.          server simply ignoring "Content-Range" would replace 
  338.          file contents with the request body instead of putting
  339.          the data at the requested place but we can blame it 
  340.          for not being compliant in this case ;)
  341.          (TODO: maybe we should do a HTTP version check first?)
  342.  
  343.          we *could* emulate partial PUT support by adding local
  344.          cacheing but for now we don't want to as it adds a lot
  345.          of complexity and storage overhead to the client ...
  346.         */
  347.     }
  348.  
  349.     /**
  350.      * Stream wrapper interface eof() method
  351.      *
  352.      * @access public
  353.      * @return bool   true if end of file was reached
  354.      */
  355.     function stream_eof() 
  356.     {
  357.         // another simple one 
  358.         return $this->eof;
  359.     }
  360.  
  361.     /**
  362.      * Stream wrapper interface tell() method
  363.      *
  364.      * @access public
  365.      * @return int    current file position
  366.      */
  367.     function stream_tell() 
  368.     {
  369.         // just return the current position
  370.         return $this->position;
  371.     }
  372.  
  373.     /**
  374.      * Stream wrapper interface seek() method
  375.      *
  376.      * @access public
  377.      * @param  int    position to seek to
  378.      * @param  int    seek mode
  379.      * @return bool   true on success
  380.      */
  381.     function stream_seek($pos, $whence) 
  382.     {
  383.         switch ($whence) {
  384.         case SEEK_SET:
  385.             // absolute position
  386.             $this->position = $pos;
  387.             break;
  388.         case SEEK_CUR:
  389.             // relative position
  390.             $this->position += $pos;
  391.             break;
  392.         case SEEK_END:
  393.             // relative position form end
  394.             $this->position = $this->stat['size'] + $pos;
  395.             break;
  396.         default: 
  397.             return false;
  398.         }
  399.  
  400.         // TODO: this is rather naive (check how libc handles this)
  401.         $this->eof = false;
  402.  
  403.         return true;
  404.     }
  405.  
  406.  
  407. /**    
  408.      * Stream wrapper interface URL stat() method
  409.      *
  410.      * @access public
  411.      * @param  string URL to get stat information for
  412.      * @return array  stat information
  413.      */
  414.     function url_stat($url) 
  415.     {
  416.         // we map this one to open()/stat()/close()
  417.         // there won't be much gain in inlining this
  418.         if (!$this->stream_open($url, "r", array(), $dummy)) {
  419.             return false;
  420.         }
  421.         $stat =  $this->stream_stat();
  422.         $this->stream_close();
  423.  
  424.         return $stat;
  425.     }
  426.  
  427.  
  428.  
  429.  
  430.  
  431. /**    
  432.      * Stream wrapper interface opendir() method
  433.      *
  434.      * @access public
  435.      * @param  string directory resource URL
  436.      * @param  array  not used here
  437.      * @return bool   true on success
  438.      */
  439.     function dir_opendir($path, $options) 
  440.     {
  441.         // rewrite the request URL
  442.         if (!$this->_parse_url($path)) return false;
  443.  
  444.         // query server for WebDAV options
  445.         if (!$this->_check_options())  return false;
  446.  
  447.         if (!isset($this->dav_allow[<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-1.0.0---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_PROPFIND">HTTP_REQUEST_METHOD_PROPFIND</a>])) {
  448.             return false;
  449.         }
  450.  
  451.         // now read the directory
  452.         $req = &new HTTP_Request($this->url);
  453.         $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-1.0.0---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_PROPFIND">HTTP_REQUEST_METHOD_PROPFIND</a>);
  454.         if (is_string($this->user)) {
  455.             $req->setBasicAuth($this->user, @$this->pass);          
  456.         }
  457.         $req->addHeader("Depth", "1");
  458.         $req->addHeader("Content-Type", "text/xml");
  459.         $req->addRawPostData('<?xml version="1.0" encoding="utf-8"?>
  460. <propfind xmlns="DAV:">
  461.  <prop>
  462.   <resourcetype/>
  463.   <getcontentlength/>
  464.   <creationdate/>
  465.   <getlastmodified/>
  466.  </prop>
  467. </propfind>
  468. ');
  469.         $req->sendRequest();
  470.  
  471.         switch ($req->getResponseCode()) {
  472.         case 207: // multistatus content
  473.             $this->dirfiles = array();
  474.             $this->dirpos = 0;
  475.  
  476.             // for all returned resource entries
  477.             foreach (split("\n", $req->getResponseBody()) as $line) {
  478.                 // get the href URL
  479.                 if (ereg("href>([^<]*)", $line, $matches)) {
  480.                     // skip the directory itself
  481.                     if ($matches[1] == $this->path) {
  482.                         continue;
  483.                     }
  484.  
  485.                     // just remember the basenames to return them later with readdir()
  486.                     $this->dirfiles[] = basename($matches[1]);
  487.                 }
  488.             }
  489.             return true;
  490.  
  491.         default: 
  492.             // any other response state indicates an error
  493.             error_log("file not found");
  494.             return false;
  495.         }
  496.     }
  497.  
  498.  
  499. /**    
  500.      * Stream wrapper interface readdir() method
  501.      *
  502.      * @access public
  503.      * @return string filename
  504.      */
  505.     function dir_readdir() 
  506.     {
  507.         // bailout if directory is empty
  508.         if (!is_array($this->dirfiles)) {
  509.             return false;
  510.         }
  511.         
  512.         // bailout if we already reached end of dir
  513.         if ($this->dirpos >= count($this->dirfiles)) {
  514.             return false;
  515.         }
  516.  
  517.         // return an entry and move on
  518.         return $this->dirfiles[$this->dirpos++];
  519.     }
  520.  
  521. /**    
  522.      * Stream wrapper interface rewinddir() method
  523.      *
  524.      * @access public
  525.      */
  526.     function dir_rewinddir() 
  527.     {
  528.         // bailout if directory content info has already
  529.         // been freed
  530.         if (!is_array($this->dirfiles)) {
  531.             return false;
  532.         }
  533.  
  534.         // rewind to first entry
  535.         $this->dirpos = 0;
  536.     }
  537.  
  538. /**    
  539.      * Stream wrapper interface closedir() method
  540.      *
  541.      * @access public
  542.      */
  543.     function dir_closedir() 
  544.     {
  545.         // free stored directory content
  546.         if (is_array($this->dirfiles)) {
  547.             $this->dirfiles = false;
  548.             $this->dirpos = 0;
  549.         }
  550.     }
  551.  
  552.  
  553. /**    
  554.      * Stream wrapper interface mkdir() method
  555.      *
  556.      * @access public
  557.      * @param  string collection URL to be created
  558.      * @return bool   true on access
  559.      */
  560.     function mkdir($path) 
  561.     {
  562.         // rewrite the request URL
  563.         if (!$this->_parse_url($path)) return false;
  564.  
  565.         // query server for WebDAV options
  566.         if (!$this->_check_options())  return false;
  567.  
  568.         $req = &new HTTP_Request($this->url);
  569.         $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-1.0.0---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_MKCOL">HTTP_REQUEST_METHOD_MKCOL</a>);
  570.         if (is_string($this->user)) {
  571.             $req->setBasicAuth($this->user, @$this->pass);          
  572.         }
  573.         if ($this->locktoken) {
  574.             $req->addHeader("If", "(<{$this->locktoken}>)");
  575.         }
  576.         $req->sendRequest();
  577.  
  578.         // check the response code, anything but 201 indicates a problem
  579.         $stat = $req->getResponseCode();
  580.         switch ($stat) {
  581.         case 201:
  582.             return true;
  583.         default:
  584.             error_log("mkdir failed - "$stat);
  585.             return false;
  586.         }
  587.     }
  588.  
  589.  
  590. /**    
  591.      * Stream wrapper interface rmdir() method
  592.      *
  593.      * @access public
  594.      * @param  string collection URL to be created
  595.      * @return bool   true on access
  596.      */
  597.     function rmdir($path) 
  598.     {
  599.         // TODO: this should behave like "rmdir", currently it is more like "rm -rf"
  600.         // rewrite the request URL
  601.         if (!$this->_parse_url($path)) return false;
  602.  
  603.         // query server for WebDAV options
  604.         if (!$this->_check_options())  return false;
  605.  
  606.         $req = &new HTTP_Request($this->url);
  607.         $req->setMethod(HTTP_REQUEST_METHOD_DELETE);
  608.         if (is_string($this->user)) {
  609.             $req->setBasicAuth($this->user, @$this->pass);          
  610.         }
  611.         if ($this->locktoken) {
  612.             $req->addHeader("If", "(<{$this->locktoken}>)");
  613.         }
  614.         $req->sendRequest();
  615.  
  616.         // check the response code, anything but 204 indicates a problem
  617.         $stat = $req->getResponseCode();
  618.         switch ($stat) {
  619.         case 204:
  620.             return true;
  621.         default:
  622.             error_log("rmdir failed - "$stat);
  623.             return false;
  624.         }
  625.     }
  626.      
  627.  
  628. /**    
  629.      * Stream wrapper interface rename() method
  630.      *
  631.      * @access public
  632.      * @param  string resource URL to be moved
  633.      * @param  string resource URL to move to
  634.      * @return bool   true on access
  635.      */
  636.     function rename($path, $new_path) 
  637.     {
  638.         // rewrite the request URL
  639.         if (!$this->_parse_url($path)) return false;
  640.  
  641.         // query server for WebDAV options
  642.         if (!$this->_check_options())  return false;
  643.  
  644.         $req = &new HTTP_Request($this->url);
  645.         $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-1.0.0---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_MOVE">HTTP_REQUEST_METHOD_MOVE</a>);
  646.         if (is_string($this->user)) {
  647.             $req->setBasicAuth($this->user, @$this->pass);          
  648.         }
  649.         if ($this->locktoken) {
  650.             $req->addHeader("If", "(<{$this->locktoken}>)");
  651.         }
  652.         if (!$this->_parse_url($new_path)) return false;
  653.         $req->addHeader("Destination", $this->url);
  654.         $req->sendRequest();
  655.  
  656.         // check the response code, anything but 207 indicates a problem
  657.         $stat = $req->getResponseCode();
  658.         switch ($stat) {
  659.         case 201:
  660.         case 204:
  661.             return true;
  662.         default:
  663.             error_log("rename failed - "$stat);
  664.             return false;
  665.         }
  666.     }
  667.      
  668.  
  669.     /**
  670.      * Stream wrapper interface unlink() method
  671.      *
  672.      * @access public
  673.      * @param  string resource URL to be removed
  674.      * @return bool   true on success
  675.      */
  676.     function unlink($path) 
  677.     {
  678.         // rewrite the request URL
  679.         if (!$this->_parse_url($path)) return false;
  680.  
  681.         // query server for WebDAV options
  682.         if (!$this->_check_options())  return false;
  683.  
  684.         // is DELETE supported?
  685.         if (!isset($this->dav_allow[HTTP_REQUEST_METHOD_DELETE])) {
  686.             return false;
  687.         }       
  688.  
  689.         $req = &new HTTP_Request($this->url);
  690.         $req->setMethod(HTTP_REQUEST_METHOD_DELETE);
  691.         if (is_string($this->user)) {
  692.             $req->setBasicAuth($this->user, @$this->pass);          
  693.         }
  694.         if ($this->locktoken) {
  695.             $req->addHeader("If", "(<{$this->locktoken}>)");
  696.         }
  697.         $req->sendRequest();
  698.  
  699.         switch ($req->getResponseCode()) {
  700.         case 204: // ok
  701.             return true;
  702.         default: 
  703.             return false;
  704.         }
  705.     }
  706.         
  707.  
  708.     /**
  709.      * Static helper that registers the wrappers
  710.      *
  711.      * @access public, static
  712.      * @return bool   true on success (even if SSL doesn't work)
  713.      */
  714.     function register() 
  715.     {
  716.         // check that we have the required feature
  717.         if (!function_exists("stream_register_wrapper")) {
  718.             return false;
  719.         }
  720.  
  721.         // try to register the non-encrypted WebDAV wrapper
  722.         if (!stream_register_wrapper("webdav", "HTTP_WebDAV_Client_Stream")) {
  723.             return false;
  724.         }
  725.  
  726.         // now try to register the SSL protocol variant
  727.         // it is not critical if this fails
  728.         // TODO check whether SSL is possible with HTTP_Request
  729.         stream_register_wrapper("webdavs", "HTTP_WebDAV_Client_Stream");
  730.  
  731.         return true;
  732.     }
  733.  
  734.  
  735.     /**
  736.      * Helper function for URL analysis
  737.      *
  738.      * @access private
  739.      * @param  string  original request URL
  740.      * @return bool    true on success else false
  741.      */
  742.     function _parse_url($path) 
  743.     {
  744.         // rewrite the WebDAV url as a plain HTTP url
  745.         $url = parse_url($path);
  746.  
  747.         // detect whether plain or SSL-encrypted transfer is requested
  748.         switch ($url['scheme']) {
  749.         case "webdav":
  750.             $url['scheme'] = "http";
  751.             break;
  752.         case "webdavs":
  753.             $url['scheme'] = "https";
  754.             break;
  755.         default:
  756.             error_log("only 'webdav:' and 'webdavs:' are supported, not '$url[scheme]:'");
  757.             return false;
  758.         }
  759.  
  760.         // if a TCP port is specified we have to add it after the host
  761.         if (isset($url['port'])) {
  762.             $url['host'] .= ":$url[port]";
  763.         }
  764.  
  765.         // store the plain path for possible later use
  766.         $this->path = $url["path"];
  767.  
  768.         // now we can put together the new URL
  769.         $this->url = "$url[scheme]://$url[host]$url[path]";
  770.  
  771.         // extract authentication information
  772.         if (isset($url['user'])) {
  773.             $this->user = urldecode($url['user']);
  774.         }
  775.         if (isset($url['pass'])) {
  776.             $this->pass = urldecode($url['pass']);
  777.         }
  778.         
  779.         return true;
  780.     }
  781.  
  782.  
  783.     /**
  784.      * Helper function for WebDAV OPTIONS detection
  785.      *
  786.      * @access private
  787.      * @return bool    true on success else false
  788.      */
  789.     function _check_options() 
  790.     {
  791.         // now check OPTIONS reply for WebDAV response headers
  792.         $req = &new HTTP_Request($this->url);
  793.         $req->setMethod(HTTP_REQUEST_METHOD_OPTIONS);
  794.         if (is_string($this->user)) {
  795.             $req->setBasicAuth($this->user, @$this->pass);          
  796.         }
  797.         $req->sendRequest();
  798.         if ($req->getResponseCode() != 200) {
  799.             return false;
  800.         }
  801.  
  802.         // get the supported DAV levels and extensions
  803.         $dav = $req->getResponseHeader("DAV");
  804.         $this->dav_level = array();
  805.         foreach (explode(",", $dav) as $level) {
  806.             $this->dav_level[trim($level)] = true;
  807.         }
  808.         if (!isset($this->dav_level["1"])) {
  809.             // we need at least DAV Level 1 conformance
  810.             return false;
  811.         }
  812.         
  813.         // get the supported HTTP methods
  814.         // TODO these are not checked for WebDAV compliance yet
  815.         $allow = $req->getResponseHeader("Allow");
  816.         $this->dav_allow = array();
  817.         foreach (explode(",", $allow) as $method) {
  818.             $this->dav_allow[trim($method)] = true;
  819.         }
  820.  
  821.         // TODO check for required WebDAV methods
  822.         return true;
  823.     }
  824.  
  825.  
  826.     /**
  827.      * Stream handler interface lock() method (experimental ...)
  828.      *
  829.      * @access private
  830.      * @return bool    true on success else false
  831.      */
  832.     function stream_lock($mode) 
  833.     {
  834.         /* TODO:
  835.          - think over how to refresh locks
  836.         */
  837.         
  838.         $ret = false;
  839.  
  840.         // LOCK is only supported by DAV Level 2
  841.         if (!isset($this->dav_level["2"])) {
  842.             return false;
  843.         }
  844.  
  845.         switch ($mode & ~LOCK_NB) {
  846.         case LOCK_UN:
  847.             if ($this->locktoken) {
  848.                 $req = &new HTTP_Request($this->url);
  849.                 $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-1.0.0---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_UNLOCK">HTTP_REQUEST_METHOD_UNLOCK</a>);
  850.                 if (is_string($this->user)) {
  851.                     $req->setBasicAuth($this->user, @$this->pass);          
  852.                 }
  853.                 $req->addHeader("Lock-Token", "<{$this->locktoken}>");
  854.                 $req->sendRequest();
  855.  
  856.                 $ret = $req->getResponseCode() == 204;
  857.             }
  858.             break;
  859.  
  860.         case LOCK_SH:
  861.         case LOCK_EX:
  862.             $body = sprintf('<?xml version="1.0" encoding="utf-8" ?> 
  863. <D:lockinfo xmlns:D="DAV:"> 
  864.  <D:lockscope><D:%s/></D:lockscope> 
  865.  <D:locktype><D:write/></D:locktype> 
  866.  <D:owner>%s</D:owner> 
  867. </D:lockinfo>',
  868.                             ($mode & LOCK_SH) ? "shared" : "exclusive",
  869.                             get_class($this))// TODO better owner string
  870.             $req = &new HTTP_Request($this->url);
  871.             $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-1.0.0---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_LOCK">HTTP_REQUEST_METHOD_LOCK</a>);
  872.             if (is_string($this->user)) {
  873.                 $req->setBasicAuth($this->user, @$this->pass);          
  874.             }
  875.             if ($this->locktoken) { // needed for refreshing a lock
  876.                 $req->addHeader("Lock-Token", "<{$this->locktoken}>");
  877.             }
  878.             $req->addHeader("Timeout", "Infinite, Second-4100000000");
  879.             $req->addHeader("Content-Type", 'text/xml; charset="utf-8"');
  880.             $req->addRawPostData($body);
  881.             $req->sendRequest();
  882.  
  883.             $ret = $req->getResponseCode() == 200;          
  884.  
  885.             if ($ret) {
  886.                 $propinfo = &new HTTP_WebDAV_Client_parse_lock_response($req->getResponseBody());               
  887.                 $this->locktoken = $propinfo->locktoken;
  888.                 // TODO deal with timeout
  889.             }
  890.             break;
  891.             
  892.         default:
  893.             break;
  894.         }
  895.  
  896.         return $ret;
  897.     }
  898. }
  899.  
  900. /*
  901.  * Local variables:
  902.  * tab-width: 4
  903.  * c-basic-offset: 4
  904.  * indent-tabs-mode:nil
  905.  * End:

Documentation generated on Mon, 11 Mar 2019 15:14:38 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.