草庐IT

php - Zend_Http_Client - 从 Stream 读取?

coder 2024-04-07 原文

我想使用 Zend_Http_Client 访问新的 Twitter Stream API。问题是,对该网页 ( http://stream.twitter.com/1/statuses/sample.json ) 的 HTTP 请求从未完成但一直在加载。

所以即使我将 Zend_Http_Client 设置为 setStream(),我也无法获取它发出的信息。

这是我目前的逻辑:

    $httpClient = new Zend_Http_Client("http://stream.twitter.com/1/statuses/sample.json");
    $httpClient->setAuth("username", "password");
    $httpClient->setStream("/tmp/twitter_stream");

    flush();
    ob_flush();

    $response = $httpClient->request("GET");

    // Never get here... :(
    Zend_Debug::dump($response);
    flush();
    ob_flush();

    while(true)
    {
        echo fgets($response->getStream());
        flush();
        ob_flush();
    }

现在,一旦我开始请求,我就永远不会进入 while 循环。 Zend Framework 所做的是,它写入一个文件。

我之所以要使用 Zend_Http_Client 是因为我以后必须使用 OAuth 访问该 Stream API,而 Zend_Oauth 依赖于 Zend_Http_Client。

如有任何帮助,我们将不胜感激。

最佳答案

据我所知,目前唯一可能的方法是扩展 Zend_Http_Client_Adapter_Socket,从旧的 Zend_Client_Http_Adapter_Socket 复制 write 方法并将您的自定义逻辑插入 do...while 循环(参见//CUSTOM LOGIC此处在方法的末尾评论):

<?php

class App_Http_Client_Adapter_Socket extends Zend_Http_Client_Adapter_Socket
{

    /**
     * Read response from server
     *
     * @return string
     */
    public function read()
    {
        // First, read headers only
        $response = '';
        $gotStatus = false;
        $stream = !empty($this->config['stream']);

        while (($line = @fgets($this->socket)) !== false)
        {
            $gotStatus = $gotStatus || (strpos($line, 'HTTP') !== false);
            if ($gotStatus)
            {
                $response .= $line;
                if (rtrim($line) === '')
                    break;
            }
        }

        $this->_checkSocketReadTimeout();

        $statusCode = Zend_Http_Response::extractCode($response);

        // Handle 100 and 101 responses internally by restarting the read again
        if ($statusCode == 100 || $statusCode == 101)
            return $this->read();

        // Check headers to see what kind of connection / transfer encoding we have
        $headers = Zend_Http_Response::extractHeaders($response);

        /**
         * Responses to HEAD requests and 204 or 304 responses are not expected
         * to have a body - stop reading here
         */
        if ($statusCode == 304 || $statusCode == 204 ||
                        $this->method == Zend_Http_Client::HEAD)
        {

            // Close the connection if requested to do so by the server
            if (isset($headers['connection']) && $headers['connection'] == 'close')
            {
                $this->close();
            }
            return $response;
        }

        // If we got a 'transfer-encoding: chunked' header
        if (isset($headers['transfer-encoding']))
        {

            if (strtolower($headers['transfer-encoding']) == 'chunked')
            {

                do
                {
                    $line = @fgets($this->socket);
                    $this->_checkSocketReadTimeout();

                    $chunk = $line;

                    // Figure out the next chunk size
                    $chunksize = trim($line);
                    if (!ctype_xdigit($chunksize))
                    {
                        $this->close();
                        require_once 'Zend/Http/Client/Adapter/Exception.php';
                        throw new Zend_Http_Client_Adapter_Exception('Invalid chunk size "' .
                                        $chunksize . '" unable to read chunked body');
                    }

                    // Convert the hexadecimal value to plain integer
                    $chunksize = hexdec($chunksize);

                    // Read next chunk
                    $read_to = ftell($this->socket) + $chunksize;

                    do
                    {
                        $current_pos = ftell($this->socket);
                        if ($current_pos >= $read_to)
                            break;

                        if ($this->out_stream)
                        {
                            if (stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0)
                            {
                                $this->_checkSocketReadTimeout();
                                break;
                            }
                        }
                        else
                        {
                            $line = @fread($this->socket, $read_to - $current_pos);
                            if ($line === false || strlen($line) === 0)
                            {
                                $this->_checkSocketReadTimeout();
                                break;
                            }
                            $chunk .= $line;
                        }
                    }
                    while (!feof($this->socket));

                    $chunk .= @ fgets($this->socket);
                    $this->_checkSocketReadTimeout();

                    if (!$this->out_stream)
                    {
                        $response .= $chunk;
                    }
                }
                while ($chunksize > 0);
            }
            else
            {
                $this->close();
                require_once 'Zend/Http/Client/Adapter/Exception.php';
                throw new Zend_Http_Client_Adapter_Exception('Cannot handle "' .
                                $headers['transfer-encoding'] . '" transfer encoding');
            }

            // We automatically decode chunked-messages when writing to a stream
            // this means we have to disallow the Zend_Http_Response to do it again
            if ($this->out_stream)
            {
                $response = str_ireplace("Transfer-Encoding: chunked\r\n", '', $response);
            }
            // Else, if we got the content-length header, read this number of bytes
        }
        elseif (isset($headers['content-length']))
        {

            // If we got more than one Content-Length header (see ZF-9404) use
            // the last value sent
            if (is_array($headers['content-length']))
            {
                $contentLength = $headers['content-length'][count($headers['content-length']) - 1];
            }
            else
            {
                $contentLength = $headers['content-length'];
            }

            $current_pos = ftell($this->socket);
            $chunk = '';

            for ($read_to = $current_pos + $contentLength; $read_to > $current_pos; $current_pos = ftell($this->socket))
            {

                if ($this->out_stream)
                {
                    if (@stream_copy_to_stream($this->socket, $this->out_stream, $read_to - $current_pos) == 0)
                    {
                        $this->_checkSocketReadTimeout();
                        break;
                    }
                }
                else
                {
                    $chunk = @fread($this->socket, $read_to - $current_pos);
                    if ($chunk === false || strlen($chunk) === 0)
                    {
                        $this->_checkSocketReadTimeout();
                        break;
                    }

                    $response .= $chunk;
                }

                // Break if the connection ended prematurely
                if (feof($this->socket))
                    break;
            }

            // Fallback: just read the response until EOF
        } else
        {

            do
            {
                if ($this->out_stream)
                {
                    if (@stream_copy_to_stream($this->socket, $this->out_stream) == 0)
                    {
                        $this->_checkSocketReadTimeout();
                        break;
                    }
                }
                else
                {
                    $buff = @fread($this->socket, 8192);
                    if ($buff === false || strlen($buff) === 0)
                    {
                        $this->_checkSocketReadTimeout();
                        break;
                    }
                    else
                    {
                        $response .= $buff;
                    }

                    // CUSTOM LOGIC HERE!!    
                    echo $response;
                    flush();
                    ob_flush();
                }
            }
            while (feof($this->socket) === false);

            $this->close();
        }

        // Close the connection if requested to do so by the server
        if (isset($headers['connection']) && $headers['connection'] == 'close')
        {
            $this->close();
        }

        return $response;
    }
}

仍然非常欢迎任何其他建议,因为我觉得这更像是一种 hack 而不是有效的解决方案。

关于php - Zend_Http_Client - 从 Stream 读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3457015/

有关php - Zend_Http_Client - 从 Stream 读取?的更多相关文章

  1. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  2. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  3. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. python - 如何读取 MIDI 文件、更改其乐器并将其写回? - 2

    我想解析一个已经存在的.mid文件,改变它的乐器,例如从“acousticgrandpiano”到“violin”,然后将它保存回去或作为另一个.mid文件。根据我在文档中看到的内容,该乐器通过program_change或patch_change指令进行了更改,但我找不到任何在已经存在的MIDI文件中执行此操作的库.他们似乎都只支持从头开始创建的MIDI文件。 最佳答案 MIDIpackage会为您完成此操作,但具体方法取决于midi文件的原始内容。一个MIDI文件由一个或多个音轨组成,每个音轨是十六个channel中任何一个上的

  8. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  9. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  10. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

    Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

随机推荐