[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare API - WebDAV * 4 * This file written by Jonathon Sim (for Zeald Ltd) <jsim@free.net.nz> * 5 * Provides methods for manipulating an RFC 2518 DAV repository * 6 * Copyright (C) 2002 Zeald Ltd * 7 * -------------------------------------------------------------------------* 8 * This library is part of the eGroupWare API * 9 * http://www.egroupware.org/api * 10 * ------------------------------------------------------------------------ * 11 * This library is free software; you can redistribute it and/or modify it * 12 * under the terms of the GNU Lesser General Public License as published by * 13 * the Free Software Foundation; either version 2.1 of the License, * 14 * or any later version. * 15 * This library is distributed in the hope that it will be useful, but * 16 * WITHOUT ANY WARRANTY; without even the implied warranty of * 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * 18 * See the GNU Lesser General Public License for more details. * 19 * You should have received a copy of the GNU Lesser General Public License * 20 * along with this library; if not, write to the Free Software Foundation, * 21 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 22 \**************************************************************************/ 23 24 /* $Id: class.http_dav_client.inc.php 16311 2004-08-09 13:46:03Z reinerj $ */ 25 26 /*At the moment much of this is simply a wrapper around the NET_HTTP_Client class, 27 with some other methods for parsing the returned XML etc 28 Ideally this will eventually use groupware's inbuilt HTTP class 29 */ 30 31 define ('DEBUG_DAV_CLIENT', 0); 32 define ('DEBUG_DAV_XML', 0); 33 define ('DEBUG_CACHE', 0); 34 35 36 ############################################################## 37 # 'Private' classes - these are only used internally and should 38 # not be used by external code 39 ############################################################## 40 41 /* 42 PHP STILL doesnt have any sort of stable DOM parser. So lets make our 43 own XML parser, that parses XML into a tree of arrays (I know, it could do 44 something resembling DOM, but it doesnt!) 45 */ 46 class xml_tree_parser 47 { 48 var $namespaces; 49 var $current_element; 50 var $num = 1; 51 var $tree = NULL; 52 53 /* 54 This is the only end-user function in the class. Call parse with an XML string, and 55 you will get back the tree of 'element' arrays 56 */ 57 function parse($xml_string) 58 { 59 $this->xml_parser = xml_parser_create(); 60 xml_set_element_handler($this->xml_parser,array(&$this,"start_element"),array(&$this,"end_element")); 61 xml_set_character_data_handler($this->xml_parser,array(&$this,"parse_data")); 62 63 $this->parser_result=array(); 64 $this->xml = $xml_string; 65 xml_parse($this->xml_parser,$xml_string); 66 xml_parser_free($this->xml_parser); 67 if (DEBUG_DAV_XML) 68 { 69 echo '<pre>'.htmlentities($xml_string).'</pre>'; 70 echo 'parsed to:' ; $this->print_tree(); 71 } 72 return $this->tree; 73 } 74 75 //a useful function for debug output - will print the tree after parsing 76 function print_tree($element=NULL, $prefix='|', $processed=array()) 77 { 78 79 if ($processed[$element['id']]) 80 { 81 echo '<b>***RECURSION!!***</b></br>'; 82 die(); 83 } 84 else 85 { 86 $processed[$element['id']] = true; 87 } 88 89 if ($element == NULL) 90 { 91 $element = $this->tree; 92 } 93 echo $prefix.$element['namespace'].':'.$element['name'].' '.$element['start'].'->'.$element['end'].'<br>'; 94 $prefix .= '-->'; 95 if ($element['data']) 96 { 97 echo $prefix.$element['data'].'<br>'; 98 } 99 100 foreach ($element['children'] as $id=>$child) 101 { 102 $this->print_tree($child, $prefix, &$processed); 103 } 104 105 } 106 107 //called by the xml parser at the start of an element, it creates that elements node in the tree 108 function start_element($parser,$name,$attr) 109 { 110 111 if (preg_match('/(.*):(.*)/', $name, $matches)) 112 { 113 $ns = $this->namespaces[$matches[1]]; 114 $element = $matches[2]; 115 } 116 else 117 { 118 $element = $name; 119 } 120 121 if ($this->tree == NULL) 122 { 123 $this->tree = array( 124 'namespace'=>$ns, 125 'name' => $element, 126 'attributes' => $attr, 127 'data' => '', 128 'children' => array(), 129 'parent' => NULL, 130 'type' => 'xml_element', 131 'id' => $this->num 132 ); 133 $this->current_element = &$this->tree; 134 } 135 else 136 { 137 $parent = &$this->current_element; 138 $parent['children'][$this->num]=array( 139 'namespace'=>$ns, 140 'name' => $element, 141 'attributes' => $attr, 142 'data' => '', 143 'children' => array(), 144 'parent' => &$parent, 145 'type' => 'xml_element', 146 'id' => $this->num 147 ); 148 $this->current_element = &$parent['children'][$this->num]; 149 } 150 $this->num++; 151 $this->current_element['start'] = xml_get_current_byte_index($parser); 152 foreach ($attr as $name => $value) 153 { 154 if (ereg('^XMLNS:(.*)', $name, $matches) ) 155 { 156 $this->namespaces[$matches[1]] = $value; 157 } 158 } 159 } 160 161 //at the end of an element, stores the start and end positions in the xml stream, and moves up the tree 162 function end_element($parser,$name) 163 { 164 $curr = xml_get_current_byte_index($parser); 165 $this->current_element['end'] =strpos($this->xml, '>', $curr); 166 $this->current_element = &$this->current_element['parent']; 167 168 } 169 170 //if there is a CDATA element, puts it into the parent elements node 171 function parse_data($parser,$data) 172 { 173 $this->current_element['data']=$data; 174 } 175 176 } 177 178 /*This class uses a bunch of recursive functions to process the DAV XML tree 179 digging out the relevent information and putting it into an array 180 */ 181 class dav_processor 182 { 183 function dav_processor($xml_string) 184 { 185 $this->xml = $xml_string; 186 $this->dav_parser = new xml_tree_parser(); 187 $this->tree = $this->dav_parser->parse($xml_string); 188 189 } 190 191 function process_tree(&$element, &$result_array) 192 { 193 194 //This lets us mark a node as 'done' and provides protection against infinite loops 195 if ($this->processed[$element['id']]) 196 { 197 return $result_array; 198 } 199 else 200 { 201 $this->processed[$element['id']] = true; 202 } 203 204 if ( $element['namespace'] == 'DAV:') 205 { 206 if ($element['name'] == 'RESPONSE') 207 { 208 $result = array( 209 'size' => 0, 210 'getcontenttype' => 'application/octet-stream', 211 'is_dir' => 0 212 ); 213 foreach ($element['children'] as $id=>$child) 214 { 215 $this->process_properties($child, $result); 216 } 217 $result_array[$result['full_name']] = $result; 218 219 } 220 } 221 // ->recursion 222 foreach ($element['children'] as $id=>$child) 223 { 224 $this->process_tree($child, $result_array); 225 } 226 return $result_array; 227 } 228 229 function process_properties($element, &$result_array) 230 { 231 if ($this->processed[$element['id']]) 232 { 233 return $result_array; 234 } 235 else 236 { 237 $this->processed[$element['id']] = true; 238 } 239 240 if ( $element['namespace'] == 'DAV:') 241 { 242 switch ($element['name']) 243 { 244 case 'HREF': 245 $string = $element['data']; 246 $idx=strrpos($string,SEP); 247 if($idx && $idx==strlen($string)-1) 248 { 249 $this->current_ref=substr($string,0,$idx); 250 } 251 else 252 { 253 $this->current_ref=$string; 254 } 255 $result_array['name']=basename($string); 256 $result_array['directory']=dirname($string); 257 $result_array['full_name'] = $this->current_ref; 258 break; 259 case 'SUPPORTEDLOCK': 260 if (count($element['children'])) //There are active locks 261 { 262 $result_array['supported_locks'] = array(); 263 foreach ($element['children'] as $id=>$child) 264 { 265 $this->process_properties($child, $result_array['supported_locks']); 266 } 267 } 268 break; 269 case 'LOCKDISCOVERY': 270 if (count($element['children'])) //There are active locks 271 { 272 $result_array['locks'] = array(); 273 foreach ($element['children'] as $id=>$child) 274 { 275 $this->process_properties($child, $result_array['locks']); 276 } 277 } 278 break; 279 case 'LOCKENTRY': 280 if (count($element['children'])) 281 { 282 $result_array[$element['id']] = array(); 283 foreach ($element['children'] as $id=>$child) 284 { 285 $this->process_properties($child, $result_array[$element['id']] ); 286 } 287 } 288 break; 289 case 'ACTIVELOCK': 290 if (count($element['children'])) 291 { 292 $result_array[$element['id']] = array(); 293 foreach ($element['children'] as $id=>$child) 294 { 295 $this->process_properties($child, $result_array[$element['id']] ); 296 } 297 } 298 break; 299 case 'OWNER': 300 $result_array['owner'] = array(); 301 302 foreach ($element['children'] as $child) 303 { 304 $this->process_verbatim($child, &$result_array['owner'][]); 305 } 306 307 //print_r($element);die(); 308 //die(); 309 $result_array['owner_xml'] = substr($this->xml, $element['start'], $element['end']-$element['start']+1); 310 return $result_array; //No need to process this branch further 311 break; 312 case 'LOCKTOKEN': 313 if (count($element['children'])) 314 { 315 316 foreach ($element['children'] as $id=>$child) 317 { 318 $this->process_properties($child, $tmp_result , $processed); 319 $result_array['lock_tokens'][$tmp_result['full_name']] = $tmp_result; 320 } 321 } 322 break; 323 case 'LOCKTYPE': 324 $child = end($element['children']); 325 if ($child) 326 { 327 $this->processed[$child['id']] = true; 328 $result_array['locktype'] = $child['name']; 329 } 330 break; 331 case 'LOCKSCOPE': 332 $child = end($element['children']); 333 if ($child) 334 { 335 $this->processed[$child['id']] = true; 336 $result_array['lockscope'] = $child['name']; 337 } 338 break; 339 default: 340 if (trim($element['data'])) 341 { 342 $result_array[strtolower($element['name'])] = $element['data']; 343 } 344 } 345 } 346 else 347 { 348 if (trim($element['data'])) 349 { 350 $result_array[strtolower($element['name'])] = $element['data']; 351 } 352 } 353 354 foreach ($element['children'] as $id=>$child) 355 { 356 $this->process_properties($child, $result_array); 357 } 358 359 return $result_array; 360 } 361 362 function process_verbatim($element, &$result_array) 363 { 364 if ($this->processed[$element['id']]) 365 { 366 return $result_array; 367 } 368 else 369 { 370 $this->processed[$element['id']] = true; 371 } 372 373 foreach ( $element as $key => $value) 374 { 375 //The parent link is death to naive programmers (eg me) :) 376 if (!( $key == 'children' || $key == 'parent') ) 377 { 378 $result_array[$key] = $value; 379 } 380 } 381 $result_array['children'] = array(); 382 foreach ($element['children'] as $id=>$child) 383 { 384 echo 'processing child:'; 385 $this->process_verbatim($child, $result_array['children']); 386 } 387 return $result_array; 388 } 389 } 390 391 ##################################################### 392 #This is the actual public interface of this class 393 ##################################################### 394 class http_dav_client 395 { 396 var $attributes=array(); 397 var $vfs_property_map = array(); 398 var $cached_props = array(); 399 function http_dav_client() 400 { 401 $this->http_client = CreateObject('phpgwapi.net_http_client'); 402 $this->set_debug(0); 403 } 404 405 //TODO: Get rid of this 406 //A quick, temporary debug output function 407 function debug($info) { 408 409 if (DEBUG_DAV_CLIENT) 410 { 411 echo '<b> http_dav_client debug:<em> '; 412 if (is_array($info)) 413 { 414 print_r($info); 415 } 416 else 417 { 418 echo $info; 419 } 420 echo '</em></b><br>'; 421 } 422 } 423 /*! 424 @function glue_url 425 @abstract glues a parsed url (ie parsed using PHP's parse_url) back 426 together 427 @param $url The parsed url (its an array) 428 */ 429 430 function glue_url ($url){ 431 if (!is_array($url)) 432 { 433 return false; 434 } 435 // scheme 436 $uri = (!empty($url['scheme'])) ? $url['scheme'].'://' : ''; 437 // user & pass 438 if (!empty($url['user'])) 439 { 440 $uri .= $url['user']; 441 if (!empty($url['pass'])) 442 { 443 $uri .=':'.$url['pass']; 444 } 445 $uri .='@'; 446 } 447 // host 448 $uri .= $url['host']; 449 // port 450 $port = (!empty($url['port'])) ? ':'.$url['port'] : ''; 451 $uri .= $port; 452 // path 453 $uri .= $url['path']; 454 // fragment or query 455 if (isset($url['fragment'])) 456 { 457 $uri .= '#'.$url['fragment']; 458 } elseif (isset($url['query'])) 459 { 460 $uri .= '?'.$url['query']; 461 } 462 return $uri; 463 } 464 465 /*! 466 @function encodeurl 467 @abstract encodes a url from its "display name" to something the dav server will accept 468 @param uri The unencoded uri 469 @discussion 470 Deals with "url"s which may contain spaces and other unsavoury characters, 471 by using appropriate %20s 472 */ 473 function encodeurl($uri) 474 { 475 $parsed_uri = parse_url($uri); 476 if (empty($parsed_uri['scheme'])) 477 { 478 $path = $uri; 479 } 480 else 481 { 482 $path = $parsed_uri['path']; 483 } 484 $fixed_array = array(); 485 foreach (explode('/', $path) as $name) 486 { 487 $fixed_array[] = rawurlencode($name); 488 } 489 $fixed_path = implode('/', $fixed_array); 490 if (!empty($parsed_uri['scheme'])) 491 { 492 $parsed_uri['path'] = $fixed_path; 493 $newuri = $this->glue_url($parsed_uri); 494 } 495 else 496 { 497 $newuri = $fixed_path; 498 } 499 return $newuri; 500 501 } 502 /*! 503 @function decodeurl 504 @abstract decodes a url to its "display name" 505 @param uri The encoded uri 506 @discussion 507 Deals with "url"s which may contain spaces and other unsavoury characters, 508 by using appropriate %20s 509 */ 510 function decodeurl($uri) 511 { 512 $parsed_uri = parse_url($uri); 513 if (empty($parsed_uri['scheme'])) 514 { 515 $path = $uri; 516 } 517 else 518 { 519 $path = $parsed_uri['path']; 520 } 521 $fixed_array = array(); 522 foreach (explode('/', $path) as $name) 523 { 524 $fixed_array[] = rawurldecode($name); 525 } 526 $fixed_path = implode('/', $fixed_array); 527 if (!empty($parsed_uri['scheme'])) 528 { 529 $parsed_uri['path'] = $fixed_path; 530 $newuri = $this->glue_url($parsed_uri); 531 } 532 else 533 { 534 $newuri = $fixed_path; 535 } 536 return $newuri; 537 538 } 539 /*! 540 @function set_attributes 541 @abstract Sets the "attribute map" 542 @param attributes Attributes to extract "as-is" from the DAV properties 543 @param dav_map A mapping of dav_property_name => attribute_name for attributes 544 with different names in DAV and the desired name space. 545 @discussion 546 This is mainly for use by VFS, where the VFS attributes (eg size) differ 547 from the corresponding DAV ones ("getcontentlength") 548 */ 549 function set_attributes($attributes, $dav_map) 550 { 551 $this->vfs_property_map = $dav_map; 552 $this->attributes = $attributes; 553 } 554 555 /*! 556 @function set_credentials 557 @abstract Sets authentication credentials for HTTP AUTH 558 @param username The username to connect with 559 @param password The password to connect with 560 @discussion 561 The only supported authentication type is "basic" 562 */ 563 function set_credentials( $username, $password ) 564 { 565 $this->http_client->setCredentials($username, $password ); 566 } 567 568 /*! 569 @function connect 570 @abstract connects to the server 571 @param dav_host The host to connect to 572 @param dav_port The port to connect to 573 @discussion 574 If the server requires authentication you will need to set credentials 575 with set_credentials first 576 */ 577 578 function connect($dav_host,$dav_port) 579 { 580 $this->dav_host = $dav_host; 581 $this->dav_port = $dav_port; 582 $this->http_client->addHeader('Host',$this->dav_host); 583 $this->http_client->addHeader('Connection','close'); 584 //$this->http_client->addHeader('transfer-encoding','identity'); 585 // $this->http_client->addHeader('Connection','keep-alive'); 586 // $this->http_client->addHeader('Keep-Alive','timeout=20, state="Accept,Accept-Language"'); 587 $this->http_client->addHeader('Accept-Encoding','chunked'); 588 $this->http_client->setProtocolVersion( '1.1' ); 589 $this->http_client->addHeader( 'user-agent', 'Mozilla/5.0 (compatible; eGroupWare dav_client/1; Linux)'); 590 return $this->http_client->Connect($dav_host,$dav_port); 591 } 592 function set_debug($debug) 593 { 594 $this->http_client->setDebug($debug); 595 } 596 597 /*! 598 @function disconnect 599 @abstract disconnect from the server 600 @discussion 601 When doing HTTP 1.1 we frequently close/reopen the connection 602 anyway, so this function needs to be called after any other DAV calls 603 (since if they find the connection closed, they just reopen it) 604 */ 605 606 function disconnect() 607 { 608 $this->http_client->Disconnect(); 609 } 610 611 /*! 612 @function get_properties 613 @abstract a high-level method of getting DAV properties 614 @param url The URL to get properties for 615 @param scope the 'depth' to recuse subdirectories (default 1) 616 @param sorted whether we should sort the rsulting array (default True) 617 @result array of file->property arra 618 @discussion 619 This function performs all the necessary XML parsing etc to convert DAV properties (ie XML nodes) 620 into associative arrays of properties - including doing mappings 621 from DAV property names to any desired property name format (eg the VFS one) 622 This is controlled by the attribute arrays set in the set_attributes function. 623 */ 624 function get_properties($url,$scope=1){ 625 $request_id = $url.'//'.$scope.'//'.$sorted; //A unique id for this request (for caching) 626 if ($this->cached_props[$request_id]) 627 { 628 if (DEBUG_CACHE) echo'Cache hit : cache id:'.$request_id; 629 return $this->cached_props[$request_id]; 630 } 631 else if (! $sorted && $this->cached_props[$url.'//'.$scope.'//1']) 632 { 633 if (DEBUG_CACHE) echo ' Cache hit : cache id: '.$request_id; 634 return $this->cached_props[$url.'//'.$scope.'//1']; 635 } 636 if (DEBUG_CACHE) 637 { 638 echo ' <b>Cache miss </b>: cache id: '.$request_id; 639 /* echo " cache:<pre>"; 640 print_r($this->cached_props); 641 echo '</pre>';*/ 642 } 643 644 645 if($this->propfind($url,$scope) != 207) 646 { 647 if($this->propfind($url.'/',$scope) != 207) 648 { 649 return array(); 650 } 651 } 652 $xml_result=$this->http_client->getBody(); 653 $result_array = array(); 654 $dav_processor = new dav_processor($xml_result); 655 $tmp_list = $dav_processor->process_tree($dav_processor->tree, $result_array); 656 657 foreach($tmp_list as $name=>$item) { 658 $fixed_name = $this->decodeurl($name); 659 $newitem = $item; 660 $newitem['is_dir']= ($item['getcontenttype'] =='httpd/unix-directory' ? 1 : 0); 661 $item['directory'] = $this->decodeurl($item['directory']); 662 //Since above we sawed off the protocol and host portions of the url, lets readd them. 663 if (strlen($item['directory'])) { 664 $path = $item['directory']; 665 $host = $this->dav_host; 666 $newitem['directory'] = $host.$path; 667 } 668 669 //Get any extra properties that may share the vfs name 670 foreach ($this->attributes as $num=>$vfs_name) 671 { 672 if ($item[$vfs_name]) 673 { 674 $newitem[$vfs_name] = $item[$vfs_name]; 675 } 676 } 677 678 //Map some DAV properties onto VFS ones. 679 foreach ($this->vfs_property_map as $dav_name=>$vfs_name) 680 { 681 if ($item[$dav_name]) 682 { 683 $newitem[$vfs_name] = $item[$dav_name]; 684 } 685 } 686 687 if ($newitem['is_dir'] == 1) 688 { 689 $newitem['mime_type']='Directory'; 690 } 691 692 $this->debug('<br><br>properties:<br>'); 693 $this->debug($newitem); 694 $newitem['name'] = $this->decodeurl($newitem['name']); 695 $result[$fixed_name]=$newitem; 696 if ($newitem['is_dir']==1) 697 { 698 $this->cached_props[$name.'//0//1'] = array($fixed_name=>$newitem); 699 } 700 else 701 { 702 $this->cached_props[$name.'//1//1'] = array($fixed_name=>$newitem); 703 } 704 } 705 if ($sorted) 706 { 707 ksort($result); 708 } 709 $this->cached_props[$request_id] = $result; 710 return $result; 711 } 712 713 function get($uri) 714 { 715 $uri = $this->encodeurl($uri); 716 return $this->http_client->Get($uri); 717 } 718 719 /*! 720 @function get_body 721 @abstract return the response body 722 @result string body content 723 @discussion 724 invoke it after a Get() call for instance, to retrieve the response 725 */ 726 function get_body() 727 { 728 return $this->http_client->getBody(); 729 } 730 731 /*! 732 @function get_headers 733 @abstract return the response headers 734 @result array headers received from server in the form headername => value 735 @discussion 736 to be called after a Get() or Head() call 737 */ 738 function get_headers() 739 { 740 return $this->http_client->getHeaders(); 741 } 742 743 /*! 744 @function copy 745 @abstract PUT is the method to sending a file on the server. 746 @param uri the location of the file on the server. dont forget the heading "/" 747 @param data the content of the file. binary content accepted 748 @result string response status code 201 (Created) if ok 749 */ 750 function put($uri, $data, $token='') 751 { 752 $uri = $this->encodeurl($uri); 753 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 754 if (strlen($token)) 755 { 756 $this->http_client->addHeader('If', '<'.$uri.'>'.' (<'.$token.'>)'); 757 } 758 759 $this->cached_props = array(); 760 $result = $this->http_client->Put($uri, $data); 761 $this->http_client->removeHeader('If'); 762 return $result; 763 } 764 765 /*! 766 @function copy 767 @abstract Copy a file -allready on the server- into a new location 768 @param srcUri the current file location on the server. dont forget the heading "/" 769 @param destUri the destination location on the server. this is *not* a full URL 770 @param overwrite boolean - true to overwrite an existing destination - overwrite by default 771 @result Returns the HTTP status code 772 @discussion 773 returns response status code 204 (Unchanged) if ok 774 */ 775 function copy( $srcUri, $destUri, $overwrite=true, $scope=0, $token='') 776 { 777 $srcUri = $this->encodeurl($srcUri); 778 $destUri = $this->encodeurl($destUri); 779 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 780 if (strlen($token)) 781 { 782 $this->http_client->addHeader('If', '<'.$uri.'>'.' (<'.$token.'>)'); 783 } 784 $this->cached_props = array(); 785 $result = $this->http_client->Copy( $srcUri, $destUri, $overwrite, $scope); 786 $this->http_client->removeHeader('If'); 787 return $result; 788 } 789 790 /*! 791 @function move 792 @abstract Moves a WEBDAV resource on the server 793 @param srcUri the current file location on the server. dont forget the heading "/" 794 @param destUri the destination location on the server. this is *not* a full URL 795 @param overwrite boolean - true to overwrite an existing destination (default is yes) 796 @result Returns the HTTP status code 797 @discussion 798 returns response status code 204 (Unchanged) if ok 799 */ 800 function move( $srcUri, $destUri, $overwrite=true, $scope=0, $token='' ) 801 { 802 $srcUri = $this->encodeurl($srcUri); 803 $destUri = $this->encodeurl($destUri); 804 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 805 if (strlen($token)) 806 { 807 $this->http_client->addHeader('If', '<'.$uri.'>'.' (<'.$token.'>)'); 808 } 809 $this->cached_props = array(); 810 $result = $this->http_client->Move( $srcUri, $destUri, $overwrite, $scope); 811 $this->http_client->removeHeader('If'); 812 return $result; 813 } 814 815 /*! 816 @function delete 817 @abstract Deletes a WEBDAV resource 818 @param uri The URI we are deleting 819 @result Returns the HTTP status code 820 @discussion 821 returns response status code 204 (Unchanged) if ok 822 */ 823 function delete( $uri, $scope=0, $token='') 824 { 825 $uri = $this->encodeurl($uri); 826 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 827 if (strlen($token)) 828 { 829 $this->http_client->addHeader('If', '<'.$uri.'>'.' (<'.$token.'>)'); 830 } 831 832 $this->cached_props = array(); 833 $result = $this->http_client->Delete( $uri, $scope); 834 $this->http_client->removeHeader('If'); 835 return $result; 836 } 837 838 /*! 839 @function mkcol 840 @abstract Creates a WEBDAV collection (AKA a directory) 841 @param uri The URI to create 842 @result Returns the HTTP status code 843 */ 844 function mkcol( $uri, $token='' ) 845 { 846 $uri = $this->encodeurl($uri); 847 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 848 if (strlen($token)) 849 { 850 $this->http_client->addHeader('If', '<'.$uri.'>'.' (<'.$token.'>)'); 851 } 852 $this->cached_props = array(); 853 return $this->http_client->MkCol( $uri ); 854 $this->http_client->removeHeader('If'); 855 } 856 857 /*! 858 @function propfind 859 @abstract Queries WEBDAV properties 860 @param uri uri of resource whose properties we are changing 861 @param scope Specifies how "deep" to search (0=just this file/dir 1=subfiles/dirs etc) 862 @result Returns the HTTP status code 863 @discussion 864 to get the result XML call get_body() 865 */ 866 function propfind( $uri, $scope=0 ) 867 { 868 $uri = $this->encodeurl($uri); 869 return $this->http_client->PropFind( $uri, $scope); 870 } 871 /*! 872 @function proppatch 873 @abstract Sets DAV properties 874 @param uri uri of resource whose properties we are changing 875 @param attributes An array of attributes and values. 876 @param namespaces Extra namespace definitions that apply to the properties 877 @result Returns the HTTP status code 878 @discussion 879 To make DAV properties useful it helps to use a well established XML dialect 880 such as the "Dublin Core" 881 882 */ 883 function proppatch($uri, $attributes, $namespaces='', $token='') 884 { 885 $uri = $this->encodeurl($uri); 886 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 887 if (strlen($token)) 888 { 889 $this->http_client->addHeader('If', '<'.$uri.'>'.' (<'.$token.'>)'); 890 } 891 $this->cached_props = array(); 892 //Begin evil nastiness 893 $davxml = '<?xml version="1.0" encoding="utf-8" ?> 894 <D:propertyupdate xmlns:D="DAV:"'; 895 896 if ($namespaces) 897 { 898 $davxml .= ' ' . $namespaces; 899 } 900 $davxml .= ' >'; 901 foreach ($attributes as $name => $value) 902 { 903 $davxml .= ' 904 <D:set> 905 <D:prop> 906 <'.$name.'>'.utf8_encode(htmlspecialchars($value)).'</'.$name.'> 907 </D:prop> 908 </D:set> 909 '; 910 } 911 $davxml .= ' 912 </D:propertyupdate>'; 913 914 if (DEBUG_DAV_XML) { 915 echo '<b>send</b><pre>'.htmlentities($davxml).'</pre>'; 916 } 917 $this->http_client->requestBody = $davxml; 918 if( $this->http_client->sendCommand( 'PROPPATCH '.$uri.' HTTP/1.1' ) ) 919 { 920 $this->http_client->processReply(); 921 } 922 923 if (DEBUG_DAV_XML) { 924 echo '<b>Recieve</b><pre>'.htmlentities($this->http_client->getBody()).'</pre>'; 925 } 926 $this->http_client->removeHeader('If'); 927 return $this->http_client->reply; 928 } 929 930 /*! 931 @function unlock 932 @abstract unlocks a locked resource on the DAV server 933 @param uri uri of the resource we are unlocking 934 @param a 'token' for the lock (to get the token, do a propfind) 935 @result true if successfull 936 @discussion 937 Not all DAV servers support locking (its in the RFC, but many common 938 DAV servers only implement "DAV class 1" (no locking) 939 */ 940 941 function unlock($uri, $token) 942 { 943 $uri = $this->encodeurl($uri); 944 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 945 $this->cached_props = array(); 946 $this->http_client->addHeader('Lock-Token', '<'.$token.'>'); 947 $this->http_client->sendCommand( 'UNLOCK '.$uri.' HTTP/1.1'); 948 $this->http_client->removeHeader('Lock-Token'); 949 $this->http_client->processReply(); 950 if ( $this->http_client->reply == '204') 951 { 952 return true; 953 } 954 else 955 { 956 $headers = $this->http_client->getHeaders(); 957 echo $this->http_client->getBody(); 958 if ($headers['Content-Type'] == 'text/html') 959 { 960 echo $this->http_client->getBody(); 961 die(); 962 } 963 else 964 { 965 return false; 966 } 967 } 968 } 969 970 /*! 971 @function lock 972 @abstract locks a resource on the DAV server 973 @param uri uri of the resource we are locking 974 @param owner the 'owner' information for the lock (purely informative) 975 @param depth the depth to which we lock collections 976 @result true if successfull 977 @discussion 978 Not all DAV servers support locking (its in the RFC, but many common 979 DAV servers only implement "DAV class 1" (no locking) 980 */ 981 function lock($uri, $owner, $depth=0, $timeout='infinity') 982 { 983 $uri = $this->encodeurl($uri); 984 if (DEBUG_CACHE) echo '<b>cache cleared</b>'; 985 $this->cached_props = array(); 986 $body = "<?xml version=\"1.0\" encoding=\"utf-8\" ?> 987 <D:lockinfo xmlns:D='DAV:'> 988 <D:lockscope><D:exclusive/></D:lockscope>\n<D:locktype><D:write/></D:locktype> 989 <D:owner><D:href>$owner</D:href></D:owner> 990 </D:lockinfo>\n"; 991 992 $this->http_client->requestBody = utf8_encode( $body ); 993 $this->http_client->addHeader('Depth', $depth); 994 if (! (strtolower(trim($timeout)) == 'infinite')) 995 { 996 $timeout = 'Second-'.$timeout; 997 } 998 $this->http_client->addHeader('Timeout', $timeout); 999 1000 if( $this->http_client->sendCommand( "LOCK $uri HTTP/1.1" ) ) 1001 $this->http_client->processReply(); 1002 $this->http_client->removeHeader('timeout'); 1003 if ( $this->http_client->reply == '200') 1004 { 1005 return true; 1006 } 1007 else 1008 { 1009 $headers = $this->http_client->getHeaders(); 1010 echo $this->http_client->getBody(); 1011 return false; 1012 1013 } 1014 1015 } 1016 /*! 1017 @function options 1018 @abstract determines the optional HTTP features supported by a server 1019 @param uri uri of the resource we are seeking options for (or * for the whole server) 1020 @result Returns an array of option values 1021 @discussion 1022 Interesting options include "ACCESS" (whether you can read a file) and 1023 DAV (DAV features) 1024 1025 */ 1026 function options($uri) 1027 { 1028 $uri = $this->encodeurl($uri); 1029 if( $this->http_client->sendCommand( 'OPTIONS '.$uri.' HTTP/1.1' ) == '200' ) 1030 { 1031 $this->http_client->processReply(); 1032 $headers = $this->http_client->getHeaders(); 1033 return $headers; 1034 } 1035 else 1036 { 1037 return False; 1038 } 1039 } 1040 /*! 1041 @function dav_features 1042 @abstract determines the features of a DAV server 1043 @param uri uri of resource whose properties we are changing 1044 @result Returns an array of option values 1045 @discussion 1046 Likely return codes include NULL (this isnt a dav server!), 1 1047 (This is a dav server, supporting all standard DAV features except locking) 1048 2, (additionally supports locking (should also return 1)) and 1049 'version-control' (this server supports versioning extensions for this resource) 1050 */ 1051 function dav_features($uri) 1052 { 1053 $uri = $this->encodeurl($uri); 1054 $options = $this->options($uri); 1055 $dav_options = $options['DAV']; 1056 if ($dav_options) 1057 { 1058 $features=explode(',', $dav_options); 1059 } 1060 else 1061 { 1062 $features = NULL; 1063 } 1064 return $features; 1065 } 1066 /************************************************************** 1067 RFC 3253 DeltaV versioning extensions 1068 ************************************************************** 1069 These are 100% untested, and almost certainly dont work yet... 1070 eventually they will be made to work with subversion... 1071 */ 1072 1073 /*! 1074 @function report 1075 @abstract Report is a kind of extended PROPFIND - it queries properties accros versions etc 1076 @param uri uri of resource whose properties we are changing 1077 @param report the type of report desired eg DAV:version-tree, DAV:expand-property etc (see http://greenbytes.de/tech/webdav/rfc3253.html#METHOD_REPORT) 1078 @param namespace any extra XML namespaces needed for the specified properties 1079 @result Returns an array of option values 1080 @discussion 1081 From the relevent RFC: 1082 "A REPORT request is an extensible mechanism for obtaining information about 1083 a resource. Unlike a resource property, which has a single value, the value 1084 of a report can depend on additional information specified in the REPORT 1085 request body and in the REPORT request headers." 1086 */ 1087 function report($uri, $report, $properties, $namespaces='') 1088 { 1089 $uri = $this->encodeurl($uri); 1090 $davxml = '<?xml version="1.0" encoding="utf-8" ?> 1091 <D:'.$report . 'xmlns:D="DAV:"'; 1092 if ($namespaces) 1093 { 1094 $davxml .= ' ' . $namespaces; 1095 } 1096 $davxml .= ' > 1097 <D:prop>'; 1098 foreach($properties as $property) 1099 { 1100 $davxml .= '<'.$property.'/>\n'; 1101 } 1102 $davxml .= '\t<D:/prop>\n<D:/'.$report.'>'; 1103 if (DEBUG_DAV_XML) { 1104 echo '<b>send</b><pre>'.htmlentities($davxml).'</pre>'; 1105 } 1106 $this->http_client->requestBody = $davxml; 1107 if( $this->http_client->sendCommand( 'REPORT '.$uri.' HTTP/1.1' ) ) 1108 { 1109 $this->http_client->processReply(); 1110 } 1111 1112 if (DEBUG_DAV_XML) { 1113 echo '<b>Recieve</b><pre>'.htmlentities($this->http_client->getBody()).'</pre>'; 1114 } 1115 return $this->http_client->reply; 1116 } 1117 1118 } 1119
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |