2

私のクライアントの場合、複数の目的で、彼自身のシステムから DirectAdmin への API 接続に取り組んでいます。1 つはバックアップの管理です。バックアップが作成されると、ダウンロードできるようになります。

しかし、私はこれを機能させることができません。リクエストを構築するための次のコードで、HTTPSocket を使用して DirectAdmin API を使用しています。

<?php 
function query( $request, $content = '', $doSpeedCheck = 0 )
{

    $this->error = $this->warn = array();
    $this->result_status_code = NULL;

    // is our request a http:// ... ?
    if (preg_match('!^http://!i',$request))
    {
        $location = parse_url($request);
        $this->connect($location['host'],$location['port']);
        $this->set_login($location['user'],$location['pass']);

        $request = $location['path'];
        $content = $location['query'];

        if ( strlen($request) < 1 )
        {
            $request = '/';
        }

    }

    $array_headers = array(
        'User-Agent' => "HTTPSocket/$this->version",
        'Host' => ( $this->remote_port == 80 ? $this->remote_host : "$this->remote_host:$this->remote_port" ),
        'Accept' => '*/*',
        'Connection' => 'Close' );

    foreach ( $this->extra_headers as $key => $value )
    {
        $array_headers[$key] = $value;
    }

    $this->result = $this->result_header = $this->result_body = '';

    // was content sent as an array? if so, turn it into a string
    if (is_array($content))
    {
        $pairs = array();

        foreach ( $content as $key => $value )
        {
            $pairs[] = "$key=".urlencode($value);
        }

        $content = join('&',$pairs);
        unset($pairs);
    }

    $OK = TRUE;

    // instance connection
    if ($this->bind_host)
    {
        $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_bind($socket,$this->bind_host);

        if (!@socket_connect($socket,$this->remote_host,$this->remote_port))
        {
            $OK = FALSE;
        }

    }
    else
    {
        $socket = @fsockopen( $this->remote_host, $this->remote_port, $sock_errno, $sock_errstr, 10 );
    }

    if ( !$socket || !$OK )
    {
        $this->error[] = "Can't create socket connection to $this->remote_host:$this->remote_port.";
        return 0;
    }

    // if we have a username and password, add the header
    if ( isset($this->remote_uname) && isset($this->remote_passwd) )
    {
        $array_headers['Authorization'] = 'Basic '.base64_encode("$this->remote_uname:$this->remote_passwd");
    }

    // for DA skins: if $this->remote_passwd is NULL, try to use the login key system
    if ( isset($this->remote_uname) && $this->remote_passwd == NULL )
    {
        $array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}";
    }

    // if method is POST, add content length & type headers
    if ( $this->method == 'POST' )
    {
        $array_headers['Content-type'] = 'application/x-www-form-urlencoded';
        $array_headers['Content-length'] = strlen($content);
    }
    // else method is GET or HEAD. we don't support anything else right now.
    else
    {
        if ($content)
        {
            $request .= "?$content";
        }
    }

    // prepare query
    $query = "$this->method $request HTTP/1.0\r\n";
    foreach ( $array_headers as $key => $value )
    {
        $query .= "$key: $value\r\n";
    }
    $query .= "\r\n";

    // if POST we need to append our content
    if ( $this->method == 'POST' && $content )
    {
        $query .= "$content\r\n\r\n";
    }

    // query connection
    if ($this->bind_host)
    {
        socket_write($socket,$query);

        // now load results
        while ( $out = socket_read($socket,2048) )
        {
            $this->result .= $out;
        }
    }
    else
    {
        fwrite( $socket, $query, strlen($query) );

        // now load results
        $this->lastTransferSpeed = 0;
        $status = socket_get_status($socket);
        $startTime = time();
        $length = 0;
        $prevSecond = 0;
        while ( !feof($socket) && !$status['timed_out'] )
        {
            $chunk = fgets($socket,1024);
            $length += strlen($chunk);
            $this->result .= $chunk;

            $elapsedTime = time() - $startTime;

            if ( $elapsedTime > 0 )
            {
                $this->lastTransferSpeed = ($length/1024)/$elapsedTime;
            }

            if ( $doSpeedCheck > 0 && $elapsedTime > 5 && $this->lastTransferSpeed < $doSpeedCheck )
            {
                $this->warn[] = "kB/s for last 5 seconds is below 50 kB/s (~".( ($length/1024)/$elapsedTime )."), dropping connection...";
                $this->result_status_code = 503;
                break;
            }

        }

        if ( $this->lastTransferSpeed == 0 )
        {
            $this->lastTransferSpeed = $length/1024;
        }

    }

    list($this->result_header,$this->result_body) = preg_split("/\r\n\r\n/",$this->result,2);

    if ($this->bind_host)
    {
        socket_close($socket);
    }
    else
    {
        fclose($socket);
    }

    $this->query_cache[] = $query;


    $headers = $this->fetch_header();

    // what return status did we get?
    if (!$this->result_status_code)
    {
        preg_match("#HTTP/1\.. (\d+)#",$headers[0],$matches);
        $this->result_status_code = $matches[1];
    }

    // did we get the full file?
    if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) )
    {
        $this->result_status_code = 206;
    }

    // now, if we're being passed a location header, should we follow it?
    if ($this->doFollowLocationHeader)
    {
        if (!empty($headers['location']))
        {
            $this->redirectURL = $headers['location'];
            $this->query($headers['location']);
        }
    }

}
?>

私のリクエストは、次のように機能します:

header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");

$apiSocket->query('/' . $action, (array) $args);
exit;

このコードを使用して、サイズが 840.46M のファイルをダウンロードすると、(ほぼ) 空の .zip ファイルを受け取ります。Content-type ヘッダーを削除すると、次のエラーが表示されました。

致命的なエラー: 134217728 バイトの許容メモリ サイズを使い果たしました (133169436 バイトを割り当てようとしました)

確かに、これは論理エラーです。ソケットがすべての内容を文字列に保存しようとしているために、文字列が大きくなりすぎているからです。そのため、行をechoだけに変更しましたが、ほぼ正しいサイズになりましたが、zip は読み取れませんでした。これは、次の式を使用して分割されていたヘッダーを含むファイルの結果である可能性があります。

/\r\n\r\n/

それで、私の質問は、どうすればこの目標を達成できるでしょうか? 良い解決策は、ヘッダーを削除することだと思いますが、文字列を変数に保存しない場合、どうすればそれを行うことができますか?

答えを期待しています。

ヤン・ウィレム

4

0 に答える 0