使用Zend Framework从App Engine进行Android推送(GCM)

时间:2014-05-09 12:33:49

标签: php google-app-engine zend-framework google-cloud-messaging

我正在尝试使用Google App Engine上的PHP和Zend Framework实现GCM服务器。到目前为止,它在本地工作正常,但在上传到App Engine时失败并显示此消息:

以下是代码:

$ids = '....my device id....';
$apiKey = '...my api key...';

$data = array( 'message' => 'Hello World!' );
$gcm_client = new Client();
$gcm_client->setApiKey($apiKey);
$gcm_message = new Message();
$gcm_message->setTimeToLive(86400);
$gcm_message->setData($data);
$gcm_message->setRegistrationIds($ids);

$response = $gcm_client->send($gcm_message);
var_dump($response);

它失败并显示以下错误消息:

  

PHP致命错误:带消息的未捕获异常'ErrorException'   'stream_socket_client():无法连接   android.googleapis.com:443(未知错误4294967295)'   /碱/数据/家/..../后端:v1.375711862873219029 /供应商/ zendframework / Zend的-HTTP /的Zend / HTTP /客户端/适配器/ Socket.php:253

我知道App Engine不允许套接字连接并为http和https提供urlFetch包装,但是如何告诉Zend Framework使用此传输?

3 个答案:

答案 0 :(得分:0)

尝试启用结算功能。据我所知,套接字仅针对付费应用启用。

这不会向你收取任何费用(除非你超过免费配额),但应该摆脱错误。

答案 1 :(得分:0)

public function sendAndroidPushNotification($registration_ids, $message) 
{

    $registrationIds = array($registration_ids);
    $msg = array(
        'message' => $message,
        'title' => 'notification center',
        'vibrate' => 1,
        'sound' => 1
    );

    $fields = array(
        'registration_ids' => $registrationIds,
        'data' => $msg
    );

    $fields = json_encode($fields);
    $arrContextOptions=array(
        "http" => array(
            "method" => "POST",
            "header" =>
            "Authorization: key = <YOUR_APP_KEY>". "\r\n" .
            "Content-Type: application/json". "\r\n",
            "content" => $fields,
         ),
         "ssl"=>array(
             "allow_self_signed"=>true,
             "verify_peer"=>false,
         ),
    );

    $arrContextOptions = stream_context_create($arrContextOptions);
    $result = file_get_contents('https://android.googleapis.com/gcm/send', false, $arrContextOptions);

    return $result;
}

答案 2 :(得分:0)

从评论中提升了这一点 - 我最终创建了自己的类实现Zend\Http\Client\Adapter\AdapterInterface,它使用URLFetch通过使用通常的fopen和流上下文来发送POST来发送POST请求。虽然这有效,但我不确定它是最好的方法。如果可能的话,更愿意使用框架功能。

我不确定这是否会对任何人有所帮助,因为ZendFramework和AppEngine自我提出问题以来都在发展,但这是我实施的适配器:

use Zend\Http\Client\Adapter\AdapterInterface;
use Zend\Http\Client\Adapter\Exception\RuntimeException;
use Zend\Http\Client\Adapter\Exception\TimeoutException;
use Zend\Stdlib\ErrorHandler;

class URLFetchHttpAdapter implements AdapterInterface
{
    protected $stream;
    protected $options;

    /**
     * Set the configuration array for the adapter
     *
     * @param array $options
     */
    public function setOptions($options = array())
    {
        $this->options = $options;
    }

    /**
     * Connect to the remote server
     *
     * @param string $host
     * @param int $port
     * @param  bool $secure
     */
    public function connect($host, $port = 80, $secure = false)
    {
        // no connection yet - it's performed in "write" method
    }

    /**
     * Send request to the remote server
     *
     * @param string $method
     * @param \Zend\Uri\Uri $url
     * @param string $httpVer
     * @param array $headers
     * @param string $body
     *
     * @throws \Zend\Loader\Exception\RuntimeException
     * @return string Request as text
     */
    public function write($method, $url, $httpVer = '1.1', $headers = array(), $body = '')
    {
        $headers_str = '';
        foreach ($headers as $k => $v) {
            if (is_string($k))
                $v = ucfirst($k) . ": $v";
            $headers_str .= "$v\r\n";
        }

        if (!is_array($this->options))
            $this->options = array();

        $context_arr = array("http" =>
                                 array( "method" => $method,
                                        "content" => $body,
                                        "header" => $headers_str,
                                        "protocol_version" => $httpVer,
                                        'ignore_errors' => true,
                                        'follow_location' => false,
                                 ) + $this->options
        );
        $context = stream_context_create($context_arr);

        ErrorHandler::start();
        $this->stream = fopen((string)$url, 'r', null, $context);
        $error = ErrorHandler::stop();
        if (!$this->stream) {
            throw new \Zend\Loader\Exception\RuntimeException('', 0, $error);
        }
    }


    /**
     * Read response from server
     *
     * @throws \Zend\Http\Client\Adapter\Exception\RuntimeException
     * @return string
     */
    public function read()
    {
        if ($this->stream) {
            ErrorHandler::start();
            $metadata = stream_get_meta_data($this->stream);
            $headers = join("\r\n", $metadata['wrapper_data']);

            $contents = stream_get_contents($this->stream);
            $error = ErrorHandler::stop();
            if ($error)
                throw $error;

            $this->close();

            //echo $headers."\r\n\r\n".$contents;
            return $headers."\r\n\r\n".$contents;
        } else {
            throw new RuntimeException("No connection exists");
        }
    }

    /**
     * Close the connection to the server
     *
     */
    public function close()
    {
        if (is_resource($this->stream)) {
            ErrorHandler::start();
            fclose($this->stream);
            ErrorHandler::stop();
            $this->stream = null;
        }
    }

    /**
     * Check if the socket has timed out - if so close connection and throw
     * an exception
     *
     * @throws TimeoutException with READ_TIMEOUT code
     */
    protected function _checkSocketReadTimeout()
    {
        if ($this->stream) {
            $info = stream_get_meta_data($this->stream);
            $timedout = $info['timed_out'];
            if ($timedout) {
                $this->close();
                throw new TimeoutException(
                    "Read timed out after {$this->options['timeout']} seconds",
                    TimeoutException::READ_TIMEOUT
                );
            }
        }
    }

}