server.php

来自「PHP 知识管理系统(基于树结构的知识管理系统), 英文原版的PHP源码。」· PHP 代码 · 共 1,998 行 · 第 1/5 页

PHP
1,998
字号
                }
            }

            $options["stream"] = fopen("php://input", "r");

            $stat = $this->PUT($options);

            if ($stat === false) {
                $stat = "403 Forbidden";
            } else if (is_resource($stat) && get_resource_type($stat) == "stream") {
                $stream = $stat;

                $stat = $options["new"] ? "201 Created" : "204 No Content";

                if (!empty($options["ranges"])) {
                    // TODO multipart support is missing (see also above)
                    if (0 == fseek($stream, $range[0]["start"], SEEK_SET)) {
                        $length = $range[0]["end"]-$range[0]["start"]+1;
                        if (!fwrite($stream, fread($options["stream"], $length))) {
                            $stat = "403 Forbidden"; 
                        }
                    } else {
                        $stat = "403 Forbidden"; 
                    }
                } else {
                    while (!feof($options["stream"])) {
                        if (false === fwrite($stream, fread($options["stream"], 4096))) {
                            $stat = "403 Forbidden"; 
                            break;
                        }
                    }
                }

                fclose($stream);            
            } 

            $this->http_status($stat);
        } else {
            $this->http_status("423 Locked");
        }
    }

    // }}}


    // {{{ http_DELETE() 

    /**
     * DELETE method handler
     *
     * @param  void
     * @return void
     */
    function http_DELETE() 
    {
        // check RFC 2518 Section 9.2, last paragraph
        if (isset($this->_SERVER["HTTP_DEPTH"])) {
            if ($this->_SERVER["HTTP_DEPTH"] != "infinity") {
                $this->http_status("400 Bad Request");
                return;
            }
        }

        // check lock status
        if ($this->_check_lock_status($this->path)) {
            // ok, proceed
            $options         = Array();
            $options["path"] = $this->path;

            $stat = $this->DELETE($options);

            $this->http_status($stat);
        } else {
            // sorry, its locked
            $this->http_status("423 Locked");
        }
    }

    // }}}

    // {{{ http_COPY() 

    /**
     * COPY method handler
     *
     * @param  void
     * @return void
     */
    function http_COPY() 
    {
        // no need to check source lock status here 
        // destination lock status is always checked by the helper method
        $this->_copymove("copy");
    }

    // }}}

    // {{{ http_MOVE() 

    /**
     * MOVE method handler
     *
     * @param  void
     * @return void
     */
    function http_MOVE() 
    {
        if ($this->_check_lock_status($this->path)) {
            // destination lock status is always checked by the helper method
            $this->_copymove("move");
        } else {
            $this->http_status("423 Locked");
        }
    }

    // }}}


    // {{{ http_LOCK() 

    /**
     * LOCK method handler
     *
     * @param  void
     * @return void
     */
    function http_LOCK() 
    {
        $options         = Array();
        $options["path"] = $this->path;
        
        if (isset($this->_SERVER['HTTP_DEPTH'])) {
            $options["depth"] = $this->_SERVER["HTTP_DEPTH"];
        } else {
            $options["depth"] = "infinity";
        }
        
        if (isset($this->_SERVER["HTTP_TIMEOUT"])) {
            $options["timeout"] = explode(",", $this->_SERVER["HTTP_TIMEOUT"]);
        }
        
        if (empty($this->_SERVER['CONTENT_LENGTH']) && !empty($this->_SERVER['HTTP_IF'])) {
            // check if locking is possible
            if (!$this->_check_lock_status($this->path)) {
                $this->http_status("423 Locked");
                return;
            }

            // refresh lock
            $options["locktoken"] = substr($this->_SERVER['HTTP_IF'], 2, -2);
            $options["update"]    = $options["locktoken"];

            // setting defaults for required fields, LOCK() SHOULD overwrite these
            $options['owner']     = "unknown";
            $options['scope']     = "exclusive";
            $options['type']      = "write";


            $stat = $this->LOCK($options);
        } else {
            // extract lock request information from request XML payload
            $lockinfo = new _parse_lockinfo("php://input");
            if (!$lockinfo->success) {
                $this->http_status("400 bad request"); 
            }

            // check if locking is possible
            if (!$this->_check_lock_status($this->path, $lockinfo->lockscope === "shared")) {
                $this->http_status("423 Locked");
                return;
            }

            // new lock 
            $options["scope"]     = $lockinfo->lockscope;
            $options["type"]      = $lockinfo->locktype;
            $options["owner"]     = $lockinfo->owner;            
            $options["locktoken"] = $this->_new_locktoken();
            
            $stat = $this->LOCK($options);              
        }
        
        if (is_bool($stat)) {
            $http_stat = $stat ? "200 OK" : "423 Locked";
        } else {
            $http_stat = $stat;
        }
        $this->http_status($http_stat);
        
        if ($http_stat{0} == 2) { // 2xx states are ok 
            if ($options["timeout"]) {
                // more than a million is considered an absolute timestamp
                // less is more likely a relative value
                if ($options["timeout"]>1000000) {
                    $timeout = "Second-".($options['timeout']-time());
                } else {
                    $timeout = "Second-$options[timeout]";
                }
            } else {
                $timeout = "Infinite";
            }
            
            header('Content-Type: text/xml; charset="utf-8"');
            header("Lock-Token: <$options[locktoken]>");
            echo "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
            echo "<D:prop xmlns:D=\"DAV:\">\n";
            echo " <D:lockdiscovery>\n";
            echo "  <D:activelock>\n";
            echo "   <D:lockscope><D:$options[scope]/></D:lockscope>\n";
            echo "   <D:locktype><D:$options[type]/></D:locktype>\n";
            echo "   <D:depth>$options[depth]</D:depth>\n";
            echo "   <D:owner>$options[owner]</D:owner>\n";
            echo "   <D:timeout>$timeout</D:timeout>\n";
            echo "   <D:locktoken><D:href>$options[locktoken]</D:href></D:locktoken>\n";
            echo "  </D:activelock>\n";
            echo " </D:lockdiscovery>\n";
            echo "</D:prop>\n\n";
        }
    }
    

    // }}}

    // {{{ http_UNLOCK() 

    /**
     * UNLOCK method handler
     *
     * @param  void
     * @return void
     */
    function http_UNLOCK() 
    {
        $options         = Array();
        $options["path"] = $this->path;

        if (isset($this->_SERVER['HTTP_DEPTH'])) {
            $options["depth"] = $this->_SERVER["HTTP_DEPTH"];
        } else {
            $options["depth"] = "infinity";
        }

        // strip surrounding <>
        $options["token"] = substr(trim($this->_SERVER["HTTP_LOCK_TOKEN"]), 1, -1);  

        // call user method
        $stat = $this->UNLOCK($options);

        $this->http_status($stat);
    }

    // }}}

    // }}}

    // {{{ _copymove() 

    function _copymove($what) 
    {
        $options         = Array();
        $options["path"] = $this->path;

        if (isset($this->_SERVER["HTTP_DEPTH"])) {
            $options["depth"] = $this->_SERVER["HTTP_DEPTH"];
        } else {
            $options["depth"] = "infinity";
        }

        extract(parse_url($this->_SERVER["HTTP_DESTINATION"]));
        $path      = urldecode($path);
        $http_host = $host;
        if (isset($port) && $port != 80)
            $http_host.= ":$port";

        $http_header_host = preg_replace("/:80$/", "", $this->_SERVER["HTTP_HOST"]);

        if ($http_host == $http_header_host &&
            !strncmp($this->_SERVER["SCRIPT_NAME"], $path,
                     strlen($this->_SERVER["SCRIPT_NAME"]))) {
            $options["dest"] = substr($path, strlen($this->_SERVER["SCRIPT_NAME"]));
            if (!$this->_check_lock_status($options["dest"])) {
                $this->http_status("423 Locked");
                return;
            }

        } else {
            $options["dest_url"] = $this->_SERVER["HTTP_DESTINATION"];
        }

        // see RFC 2518 Sections 9.6, 8.8.4 and 8.9.3
        if (isset($this->_SERVER["HTTP_OVERWRITE"])) {
            $options["overwrite"] = $this->_SERVER["HTTP_OVERWRITE"] == "T";
        } else {
            $options["overwrite"] = true;
        }

        $stat = $this->$what($options);
        $this->http_status($stat);
    }

    // }}}

    // {{{ _allow() 

    /**
     * check for implemented HTTP methods
     *
     * @param  void
     * @return array something
     */
    function _allow() 
    {
        // OPTIONS is always there
        $allow = array("OPTIONS" =>"OPTIONS");

        // all other METHODS need both a http_method() wrapper
        // and a method() implementation
        // the base class supplies wrappers only
        foreach (get_class_methods($this) as $method) {
            if (!strncmp("http_", $method, 5)) {
                $method = strtoupper(substr($method, 5));
                if (method_exists($this, $method)) {
                    $allow[$method] = $method;
                }
            }
        }

        // we can emulate a missing HEAD implemetation using GET
        if (isset($allow["GET"]))
            $allow["HEAD"] = "HEAD";

        // no LOCK without checklok()
        if (!method_exists($this, "checklock")) {
            unset($allow["LOCK"]);
            unset($allow["UNLOCK"]);
        }

        return $allow;
    }

    // }}}

    /**
     * helper for property element creation
     *
     * @param  string  XML namespace (optional)
     * @param  string  property name
     * @param  string  property value
     * @return array   property array
     */
    function mkprop() 
    {
        $args = func_get_args();
        if (count($args) == 3) {
            return array("ns"   => $args[0], 
                         "name" => $args[1],
                         "val"  => $args[2]);
        } else {
            return array("ns"   => "DAV:", 
                         "name" => $args[0],
                         "val"  => $args[1]);
        }
    }

    // {{{ _check_auth 

    /**
     * check authentication if check is implemented
     * 
     * @param  void
     * @return bool  true if authentication succeded or not necessary
     */
    function _check_auth() 
    {
        if (method_exists($this, "checkAuth")) {
            // PEAR style method name
            return $this->checkAuth(@$this->_SERVER["AUTH_TYPE"],
                                    @$this->_SERVER["PHP_AUTH_USER"],
                                    @$this->_SERVER["PHP_AUTH_PW"]);
        } else if (method_exists($this, "check_auth")) {
            // old (pre 1.0) method name
            return $this->check_auth(@$this->_SERVER["AUTH_TYPE"],
                                     @$this->_SERVER["PHP_AUTH_USER"],
                                     @$this->_SERVER["PHP_AUTH_PW"]);
        } else {
            // no method found -> no authentication required
            return true;
        }
    }

    // }}}

    // {{{ UUID stuff 
    
    /**
     * generate Unique Universal IDentifier for lock token
     *
     * @param  void
     * @return string  a new UUID
     */
    function _new_uuid() 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?