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;
  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.             break;
  268.  
  269.         default: 
  270.             return false;
  271.         }
  272.  
  273.         // no data indicates end of file
  274.         if (!$len{
  275.             $this->eof = true;
  276.         }
  277.  
  278.         // update position
  279.         $this->position += $len;
  280.  
  281.         // thats it!
  282.         return $data;
  283.     }
  284.  
  285.     /**
  286.      * Stream wrapper interface write() method
  287.      *
  288.      * @access public
  289.      * @param  string data to write
  290.      * @return int    number of bytes actually written
  291.      */
  292.     function stream_write($buffer
  293.     {
  294.         // do some math
  295.         $start $this->position;
  296.         $end $this->position strlen($buffer);
  297.  
  298.         // create a partial PUT request
  299.         $req &new HTTP_Request($this->url);
  300.         $req->setMethod(HTTP_REQUEST_METHOD_PUT);
  301.         if (is_string($this->user)) {
  302.             $req->setBasicAuth($this->user@$this->pass);          
  303.         }
  304.         $req->addHeader("Content-Range""bytes $start-$end/*");
  305.         if ($this->locktoken{
  306.             $req->addHeader("If""(<{$this->locktoken}>)");
  307.         }
  308.         $req->addRawPostData($buffer);
  309.  
  310.         // go! go! go!
  311.         $req->sendRequest();
  312.  
  313.         // check result
  314.         switch ($req->getResponseCode()) {
  315.         case 200:
  316.         case 201:
  317.         case 204:
  318.             $this->position += strlen($buffer);
  319.             return $end $start;
  320.             
  321.         default: 
  322.             return false;
  323.         }
  324.  
  325.         /* 
  326.            We do not cope with servers that do not support partial PUTs!
  327.            And we do assume that a server does conform to the following 
  328.            rule from RFC 2616 Section 9.6:
  329.            "The recipient of the entity MUST NOT ignore any Content-* 
  330.             (e.g. Content-Range) headers that it does not understand or 
  331.             implement and MUST return a 501 (Not Implemented) response 
  332.             in such cases."
  333.            
  334.             So the worst case scenario with a compliant server not 
  335.             implementing partial PUTs should be a failed request. A 
  336.             server simply ignoring "Content-Range" would replace 
  337.             file contents with the request body instead of putting
  338.             the data at the requested place but we can blame it 
  339.             for not being compliant in this case ;)
  340.             (TODO: maybe we should do a HTTP version check first?)
  341.  
  342.             we *could* emulate partial PUT support by adding local
  343.             cacheing but for now we don't want to as it adds a lot
  344.             of complexity and storage overhead to the client ...
  345.          */
  346.     }
  347.  
  348.     /**
  349.      * Stream wrapper interface eof() method
  350.      *
  351.      * @access public
  352.      * @return bool   true if end of file was reached
  353.      */
  354.     function stream_eof() 
  355.     {
  356.         // another simple one 
  357.         return $this->eof;
  358.     }
  359.  
  360.     /**
  361.      * Stream wrapper interface tell() method
  362.      *
  363.      * @access public
  364.      * @return int    current file position
  365.      */
  366.     function stream_tell() 
  367.     {
  368.         // just return the current position
  369.         return $this->position;
  370.     }
  371.  
  372.     /**
  373.      * Stream wrapper interface seek() method
  374.      *
  375.      * @access public
  376.      * @param  int    position to seek to
  377.      * @param  int    seek mode
  378.      * @return bool   true on success
  379.      */
  380.     function stream_seek($pos, $whence) 
  381.     {
  382.         switch ($whence) {
  383.         case SEEK_SET:
  384.             // absolute position
  385.             $this->position = $pos;
  386.             break;
  387.         case SEEK_CUR:
  388.             // relative position
  389.             $this->position += $pos;
  390.             break;
  391.         case SEEK_END:
  392.             // relative position form end
  393.             $this->position = $this->stat['size'] + $pos;
  394.             break;
  395.         default: 
  396.             return false;
  397.         }
  398.  
  399.         // TODO: this is rather naive (check how libc handles this)
  400.         $this->eof = false;
  401.  
  402.         return true;
  403.     }
  404.  
  405.  
  406. /**    
  407.      * Stream wrapper interface URL stat() method
  408.      *
  409.      * @access public
  410.      * @param  string URL to get stat information for
  411.      * @return array  stat information
  412.      */
  413.     function url_stat($url) 
  414.     {
  415.         // we map this one to open()/stat()/close()
  416.         // there won't be much gain in inlining this
  417.         if (!$this->stream_open($url, "r", array(), $dummy)) {
  418.             return false;
  419.         }
  420.         $stat =  $this->stream_stat();
  421.         $this->stream_close();
  422.  
  423.         return $stat;
  424.     }
  425.  
  426.  
  427.  
  428.  
  429.  
  430. /**    
  431.      * Stream wrapper interface opendir() method
  432.      *
  433.      * @access public
  434.      * @param  string directory resource URL
  435.      * @param  array  not used here
  436.      * @return bool   true on success
  437.      */
  438.     function dir_opendir($path, $options) 
  439.     {
  440.         // rewrite the request URL
  441.         if (!$this->_parse_url($path)) return false;
  442.  
  443.         // query server for WebDAV options
  444.         if (!$this->_check_options())  return false;
  445.  
  446.         if (!isset($this->dav_allow[<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-0.9.7---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_PROPFIND">HTTP_REQUEST_METHOD_PROPFIND</a>])) {
  447.             return false;
  448.         }
  449.  
  450.         // now read the directory
  451.         $req = &new HTTP_Request($this->url);
  452.         $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-0.9.7---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_PROPFIND">HTTP_REQUEST_METHOD_PROPFIND</a>);
  453.         if (is_string($this->user)) {
  454.             $req->setBasicAuth($this->user, @$this->pass);          
  455.         }
  456.         $req->addHeader("Depth", "1");
  457.         $req->addHeader("Content-Type", "text/xml");
  458.         $req->addRawPostData('<?xml version="1.0" encoding="utf-8"?>
  459. <propfind xmlns="DAV:">
  460.  <prop>
  461.   <resourcetype/>
  462.   <getcontentlength/>
  463.   <creationdate/>
  464.   <getlastmodified/>
  465.  </prop>
  466. </propfind>
  467. ');
  468.         $req->sendRequest();
  469.  
  470.         switch ($req->getResponseCode()) {
  471.         case 207: // multistatus content
  472.             $this->dirfiles = array();
  473.             $this->dirpos = 0;
  474.  
  475.             // for all returned resource entries
  476.             foreach (split("\n",$req->getResponseBody()) as $line) {
  477.                 // get the href URL
  478.                 if (ereg("href>([^<]*)", $line, $matches)) {
  479.                     // skip the directory itself
  480.                     if ($matches[1] == $this->path) {
  481.                         continue;
  482.                     }
  483.  
  484.                     // just remember the basenames to return them later with readdir()
  485.                     $this->dirfiles[] = basename($matches[1]);
  486.                 }
  487.             }
  488.             return true;
  489.  
  490.         default: 
  491.             // any other response state indicates an error
  492.             error_log("file not found");
  493.             return false;
  494.         }
  495.     }
  496.  
  497.  
  498. /**    
  499.      * Stream wrapper interface readdir() method
  500.      *
  501.      * @access public
  502.      * @return string filename
  503.      */
  504.     function dir_readdir() 
  505.     {
  506.         // bailout if directory is empty
  507.         if (!is_array($this->dirfiles)) {
  508.             return false;
  509.         }
  510.         
  511.         // bailout if we already reached end of dir
  512.         if ($this->dirpos >= count($this->dirfiles)) {
  513.             return false;
  514.         }
  515.  
  516.         // return an entry and move on
  517.         return $this->dirfiles[$this->dirpos++];
  518.     }
  519.  
  520. /**    
  521.      * Stream wrapper interface rewinddir() method
  522.      *
  523.      * @access public
  524.      */
  525.     function dir_rewinddir() 
  526.     {
  527.         // bailout if directory content info has already
  528.         // been freed
  529.         if (!is_array($this->dirfiles)) {
  530.             return false;
  531.         }
  532.  
  533.         // rewind to first entry
  534.         $this->dirpos = 0;
  535.     }
  536.  
  537. /**    
  538.      * Stream wrapper interface closedir() method
  539.      *
  540.      * @access public
  541.      */
  542.     function dir_closedir() 
  543.     {
  544.         // free stored directory content
  545.         if (is_array($this->dirfiles)) {
  546.             $this->dirfiles = false;
  547.             $this->dirpos = 0;
  548.         }
  549.     }
  550.  
  551.  
  552. /**    
  553.      * Stream wrapper interface mkdir() method
  554.      *
  555.      * @access public
  556.      * @param  string collection URL to be created
  557.      * @return bool   true on access
  558.      */
  559.     function mkdir($path) {
  560.         // rewrite the request URL
  561.         if (!$this->_parse_url($path)) return false;
  562.  
  563.         // query server for WebDAV options
  564.         if (!$this->_check_options())  return false;
  565.  
  566.         $req = &new HTTP_Request($this->url);
  567.         $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-0.9.7---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_MKCOL">HTTP_REQUEST_METHOD_MKCOL</a>);
  568.         if (is_string($this->user)) {
  569.             $req->setBasicAuth($this->user, @$this->pass);          
  570.         }
  571.         if ($this->locktoken) {
  572.             $req->addHeader("If", "(<{$this->locktoken}>)");
  573.         }
  574.         $req->sendRequest();
  575.  
  576.         // check the response code, anything but 201 indicates a problem
  577.         $stat = $req->getResponseCode();
  578.         switch ($stat) {
  579.         case 201:
  580.             return true;
  581.         default:
  582.             error_log("mkdir failed - "$stat);
  583.             return false;
  584.         }
  585.     }
  586.  
  587.  
  588. /**    
  589.      * Stream wrapper interface rmdir() method
  590.      *
  591.      * @access public
  592.      * @param  string collection URL to be created
  593.      * @return bool   true on access
  594.      */
  595.     function rmdir($path) {
  596.         // TODO: this should behave like "rmdir", currently it is more like "rm -rf"
  597.         // rewrite the request URL
  598.         if (!$this->_parse_url($path)) return false;
  599.  
  600.         // query server for WebDAV options
  601.         if (!$this->_check_options())  return false;
  602.  
  603.         $req = &new HTTP_Request($this->url);
  604.         $req->setMethod(HTTP_REQUEST_METHOD_DELETE);
  605.         if (is_string($this->user)) {
  606.             $req->setBasicAuth($this->user, @$this->pass);          
  607.         }
  608.         if ($this->locktoken) {
  609.             $req->addHeader("If", "(<{$this->locktoken}>)");
  610.         }
  611.         $req->sendRequest();
  612.  
  613.         // check the response code, anything but 204 indicates a problem
  614.         $stat = $req->getResponseCode();
  615.         switch ($stat) {
  616.         case 204:
  617.             return true;
  618.         default:
  619.             error_log("rmdir failed - "$stat);
  620.             return false;
  621.         }
  622.     }
  623.      
  624.  
  625. /**    
  626.      * Stream wrapper interface rename() method
  627.      *
  628.      * @access public
  629.      * @param  string resource URL to be moved
  630.      * @param  string resource URL to move to
  631.      * @return bool   true on access
  632.      */
  633.     function rename($path, $new_path) {
  634.         // rewrite the request URL
  635.         if (!$this->_parse_url($path)) return false;
  636.  
  637.         // query server for WebDAV options
  638.         if (!$this->_check_options())  return false;
  639.  
  640.         $req = &new HTTP_Request($this->url);
  641.         $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-0.9.7---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_MOVE">HTTP_REQUEST_METHOD_MOVE</a>);
  642.         if (is_string($this->user)) {
  643.             $req->setBasicAuth($this->user, @$this->pass);          
  644.         }
  645.         if ($this->locktoken) {
  646.             $req->addHeader("If", "(<{$this->locktoken}>)");
  647.         }
  648.         if (!$this->_parse_url($new_path)) return false;
  649.         $req->addHeader("Destination", $this->url);
  650.         $req->sendRequest();
  651.  
  652.         // check the response code, anything but 207 indicates a problem
  653.         $stat = $req->getResponseCode();
  654.         switch ($stat) {
  655.         case 201:
  656.         case 204:
  657.             return true;
  658.         default:
  659.             error_log("rename failed - "$stat);
  660.             return false;
  661.         }
  662.     }
  663.      
  664.  
  665.     /**
  666.      * Stream wrapper interface unlink() method
  667.      *
  668.      * @access public
  669.      * @param  string resource URL to be removed
  670.      * @return bool   true on success
  671.      */
  672.     function unlink($path) 
  673.     {
  674.         // rewrite the request URL
  675.         if (!$this->_parse_url($path)) return false;
  676.  
  677.         // query server for WebDAV options
  678.         if (!$this->_check_options())  return false;
  679.  
  680.         // is DELETE supported?
  681.         if (!isset($this->dav_allow[HTTP_REQUEST_METHOD_DELETE])) {
  682.             return false;
  683.         }       
  684.  
  685.         $req = &new HTTP_Request($this->url);
  686.         $req->setMethod(HTTP_REQUEST_METHOD_DELETE);
  687.         if (is_string($this->user)) {
  688.             $req->setBasicAuth($this->user, @$this->pass);          
  689.         }
  690.         if ($this->locktoken) {
  691.             $req->addHeader("If", "(<{$this->locktoken}>)");
  692.         }
  693.         $req->sendRequest();
  694.  
  695.         switch ($req->getResponseCode()) {
  696.         case 204: // ok
  697.             return true;
  698.         default: 
  699.             return false;
  700.         }
  701.     }
  702.         
  703.  
  704.     /**
  705.      * Static helper that registers the wrappers
  706.      *
  707.      * @access public, static
  708.      * @return bool   true on success (even if SSL doesn't work)
  709.      */
  710.     function register() 
  711.     {
  712.         // check that we have the required feature
  713.         if (!function_exists("stream_register_wrapper")) {
  714.             return false;
  715.         }
  716.  
  717.         // try to register the non-encrypted WebDAV wrapper
  718.         if (!stream_register_wrapper("webdav", "HTTP_WebDAV_Client_Stream")) {
  719.             return false;
  720.         }
  721.  
  722.         // now try to register the SSL protocol variant
  723.         // it is not critical if this fails
  724.         // TODO check whether SSL is possible with HTTP_Request
  725.         stream_register_wrapper("webdavs", "HTTP_WebDAV_Client_Stream");
  726.  
  727.         return true;
  728.     }
  729.  
  730.  
  731.     /**
  732.      * Helper function for URL analysis
  733.      *
  734.      * @access private
  735.      * @param  string  original request URL
  736.      * @return bool    true on success else false
  737.      */
  738.     function _parse_url($path) 
  739.     {
  740.         // rewrite the WebDAV url as a plain HTTP url
  741.         $url = parse_url($path);
  742.  
  743.         // detect whether plain or SSL-encrypted transfer is requested
  744.         switch ($url['scheme']) {
  745.         case "webdav":
  746.             $url['scheme'] = "http";
  747.             break;
  748.         case "webdavs":
  749.             $url['scheme'] = "https";
  750.             break;
  751.         default:
  752.             error_log("only 'webdav:' and 'webdavs:' are supported, not '$url[scheme]:'");
  753.             return false;
  754.         }
  755.  
  756.         // if a TCP port is specified we have to add it after the host
  757.         if (isset($url['port'])) {
  758.             $url['host'] .= ":$url[port]";
  759.         }
  760.  
  761.         // store the plain path for possible later use
  762.         $this->path = $url["path"];
  763.  
  764.         // now we can put together the new URL
  765.         $this->url = "$url[scheme]://$url[host]$url[path]";
  766.  
  767.         // extract authentication information
  768.         if (isset($url['user'])) {
  769.             $this->user = urldecode($url['user']);
  770.         }
  771.         if (isset($url['pass'])) {
  772.             $this->pass = urldecode($url['pass']);
  773.         }
  774.         
  775.         return true;
  776.     }
  777.  
  778.  
  779.     /**
  780.      * Helper function for WebDAV OPTIONS detection
  781.      *
  782.      * @access private
  783.      * @return bool    true on success else false
  784.      */
  785.     function _check_options() 
  786.     {
  787.         // now check OPTIONS reply for WebDAV response headers
  788.         $req = &new HTTP_Request($this->url);
  789.         $req->setMethod(HTTP_REQUEST_METHOD_OPTIONS);
  790.         if (is_string($this->user)) {
  791.             $req->setBasicAuth($this->user, @$this->pass);          
  792.         }
  793.         $req->sendRequest();
  794.         if ($req->getResponseCode() != 200) {
  795.             return false;
  796.         }
  797.  
  798.         // get the supported DAV levels and extensions
  799.         $dav = $req->getResponseHeader("DAV");
  800.         $this->dav_level = array();
  801.         foreach (explode(",", $dav) as $level) {
  802.             $this->dav_level[trim($level)] = true;
  803.         }
  804.         if (!isset($this->dav_level["1"])) {
  805.             // we need at least DAV Level 1 conformance
  806.             return false;
  807.         }
  808.         
  809.         // get the supported HTTP methods
  810.         // TODO these are not checked for WebDAV compliance yet
  811.         $allow = $req->getResponseHeader("Allow");
  812.         $this->dav_allow = array();
  813.         foreach (explode(",", $allow) as $method) {
  814.             $this->dav_allow[trim($method)] = true;
  815.         }
  816.  
  817.         // TODO check for required WebDAV methods
  818.         return true;
  819.     }
  820.  
  821.  
  822.     /**
  823.      * Stream handler interface lock() method (experimental ...)
  824.      *
  825.      * @access private
  826.      * @return bool    true on success else false
  827.      */
  828.     function stream_lock($mode) {
  829.         /* TODO:
  830.            - think over how to refresh locks
  831.          */
  832.         
  833.         $ret = false;
  834.  
  835.         // LOCK is only supported by DAV Level 2
  836.         if (!isset($this->dav_level["2"])) {
  837.             return false;
  838.         }
  839.  
  840.         switch ($mode & ~LOCK_NB) {
  841.         case LOCK_UN:
  842.             if ($this->locktoken) {
  843.                 $req = &new HTTP_Request($this->url);
  844.                 $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-0.9.7---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_UNLOCK">HTTP_REQUEST_METHOD_UNLOCK</a>);
  845.                 if (is_string($this->user)) {
  846.                     $req->setBasicAuth($this->user, @$this->pass);          
  847.                 }
  848.                 $req->addHeader("Lock-Token", "<{$this->locktoken}>");
  849.                 $req->sendRequest();
  850.  
  851.                 $ret = $req->getResponseCode() == 204;
  852.             }
  853.             break;
  854.  
  855.         case LOCK_SH:
  856.         case LOCK_EX:
  857.             $body = sprintf('<?xml version="1.0" encoding="utf-8" ?> 
  858. <D:lockinfo xmlns:D="DAV:"> 
  859.  <D:lockscope><D:%s/></D:lockscope> 
  860.  <D:locktype><D:write/></D:locktype> 
  861.  <D:owner>%s</D:owner> 
  862. </D:lockinfo>'
  863.                             , ($mode & LOCK_SH) ? "shared" : "exclusive"
  864.                             , get_class($this) // TODO better owner string
  865.                             );
  866.             $req = &new HTTP_Request($this->url);
  867.             $req->setMethod(<a href="../HTTP_WebDAV_Client/_HTTP_WebDAV_Client-0.9.7---Client---Stream.php.html#defineHTTP_REQUEST_METHOD_LOCK">HTTP_REQUEST_METHOD_LOCK</a>);
  868.             if (is_string($this->user)) {
  869.                 $req->setBasicAuth($this->user, @$this->pass);          
  870.             }
  871.             if ($this->locktoken) { // needed for refreshing a lock
  872.                 $req->addHeader("Lock-Token", "<{$this->locktoken}>");
  873.             }
  874.             $req->addHeader("Timeout","Infinite, Second-4100000000");
  875.             $req->addHeader("Content-Type", 'text/xml; charset="utf-8"');
  876.             $req->addRawPostData($body);
  877.             $req->sendRequest();
  878.  
  879.             $ret = $req->getResponseCode() == 200;          
  880.  
  881.             if ($ret) {
  882.                 $propinfo = &new HTTP_WebDAV_Client_parse_lock_response($req->getResponseBody());               
  883.                 $this->locktoken = $propinfo->locktoken;
  884.                 // TODO deal with timeout
  885.             }
  886.             break;
  887.             
  888.         default:
  889.             break;
  890.         }
  891.  
  892.         return $ret;
  893.     }
  894. }
  895.  

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