source: trunk/phpgwapi/inc/class.http_dav_client.inc.php @ 2

Revision 2, 31.3 KB checked in by niltonneto, 17 years ago (diff)

Removida todas as tags usadas pelo CVS ($Id, $Source).
Primeira versão no CVS externo.

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