1. <?php
    /////////////////////////////////////////////////
    // PukiWiki - Yet another WikiWikiWeb clone.
    //
    // $Id: proxy.php,v 1.4 2003/10/01 05:38:47 arino Exp $
    //
    
    /*
     * http_request($url)
     *   HTTPリクエストを発行し、データを取得する
     * $url     : http://から始まるURL(http://user:pass@host:port/path?query)
     * $method  : GET, POST, HEADのいずれか(デフォルトはGET)
     * $headers : 任意の追加ヘッダ
     * $post    : POSTの時に送信するデータを格納した配列('変数名'=>'値')
     * $redirect_max : HTTP redirectの回数制限
    */
    
    // リダイレクト回数制限の初期値
    define('HTTP_REQUEST_URL_REDIRECT_MAX',10);
    
    function http_request($url,$method='GET',$headers='',$post=array(),
        $redirect_max=HTTP_REQUEST_URL_REDIRECT_MAX)
    {
        global $use_proxy,$proxy_host,$proxy_port;
        global $need_proxy_auth,$proxy_auth_user,$proxy_auth_pass;
        
        $rc = array();
        $arr = parse_url($url);
        
        $via_proxy = $use_proxy and via_proxy($arr['host']);
        
        // query
        $arr['query'] = isset($arr['query']) ? '?'.$arr['query'] : '';
        // port
        $arr['port'] = isset($arr['port']) ? $arr['port'] : 80;
        
        $url_base = $arr['scheme'].'://'.$arr['host'].':'.$arr['port'];
        $url_path = isset($arr['path']) ? $arr['path'] : '/';
        $url = ($via_proxy ? $url_base : '').$url_path.$arr['query'];
        
        $query = $method.' '.$url." HTTP/1.0\r\n";
        $query .= "Host: ".$arr['host']."\r\n";
        $query .= "User-Agent: PukiWiki/".S_VERSION."\r\n";
    
        // proxyのBasic認証
        if ($need_proxy_auth and isset($proxy_auth_user) and isset($proxy_auth_pass))
        {
            $query .= 'Proxy-Authorization: Basic '.
                base64_encode($proxy_auth_user.':'.$proxy_auth_pass)."\r\n";
        }
        // Basic 認証用
        if (isset($arr['user']) and isset($arr['pass']))
        {
            $query .= 'Authorization: Basic '.
                base64_encode($arr['user'].':'.$arr['pass'])."\r\n";
        }
        
        $query .= $headers;
        
        // POST 時は、urlencode したデータとする
        if (strtoupper($method) == 'POST')
        {
            $POST = array();
            foreach ($post as $name=>$val)
            {
                $POST[] = $name.'='.urlencode($val);
            }
            $data = join('&',$POST);
            $query .= "Content-Type: application/x-www-form-urlencoded\r\n";
            $query .= 'Content-Length: '.strlen($data)."\r\n";
            $query .= "\r\n";
            $query .= $data;
        }
        else
        {
            $query .= "\r\n";
        }
        
        $fp = fsockopen(
            $via_proxy ? $proxy_host : $arr['host'],
            $via_proxy ? $proxy_port : $arr['port'],
            $errno,$errstr,30);
        if (!$fp)
        {
            return array(
                'query'  => $query, // Query String
                'rc'     => $errno, // エラー番号
                'header' => '',     // Header
                'data'   => $errstr // エラーメッセージ
            );
        }
        
        fputs($fp, $query);
        
        $response = '';
        while (!feof($fp))
        {
            $response .= fread($fp,4096);
        }
        fclose($fp);
        
        $resp = explode("\r\n\r\n",$response,2);
        $rccd = explode(' ',$resp[0],3); // array('HTTP/1.1','200','OK\r\n...')
        $rc = (integer)$rccd[1];
        
        // Redirect
        switch ($rc)
        {
            case 302: // Moved Temporarily
            case 301: // Moved Permanently
                if (preg_match('/^Location: (.+)$/m',$resp[0],$matches)
                    and --$redirect_max > 0)
                {
                    $url = trim($matches[1]);
                    if (!preg_match('/^https?:\//',$url)) // no scheme
                    {
                        if ($url{0} != '/') // Relative path
                        {
                            // to Absolute path
                            $url = substr($url_path,0,strrpos($url_path,'/')).'/'.$url;
                        }
                        // add sheme,host
                        $url = $url_base.$url;
                    } 
                    return http_request($url,$method,$headers,$post,$redirect_max);
                }
        }
        
        return array(
            'query'  => $query,   // Query String
            'rc'     => $rc,      // Response Code
            'header' => $resp[0], // Header
            'data'   => $resp[1]  // Data
        );
    }
    // プロキシを経由する必要があるかどうか判定
    function via_proxy($host)
    {
        global $use_proxy,$no_proxy;
        static $ip_pattern = '/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?:\/(.+))?$/';
        
        if (!$use_proxy)
        {
            return FALSE;
        }
        $ip = gethostbyname($host);
        $l_ip = ip2long($ip);
        $valid = (is_long($l_ip) and long2ip($l_ip) == $ip); // valid ip address
        
        foreach ($no_proxy as $network)
        {
            if ($valid and preg_match($ip_pattern,$network,$matches))
            {
                $l_net = ip2long($matches[1]);
                $mask = array_key_exists(2,$matches) ? $matches[2] : 32;
                $mask = is_numeric($mask) ?
                    pow(2,32) - pow(2,32 - $mask) : // "10.0.0.0/8"
                    ip2long($mask);                 // "10.0.0.0/255.0.0.0"
                if (($l_ip & $mask) == $l_net)
                {
                    return FALSE;
                }
            }
            else
            {
                if (preg_match('/'.preg_quote($network,'/').'/',$host))
                {
                    return FALSE;
                }
            }
        }
        return TRUE;
    }
    ?>