【问题标题】:Android push (GCM) from App Engine using Zend Framework使用 Zend Framework 从 App Engine 推送 Android 推送 (GCM)
【发布时间】:2014-06-27 04:54:07
【问题描述】:

我正在尝试在 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)' /base/data/home/../backend:v1.375711862873219029/vendor/zendframework/zend-http/Zend/Http/Client/Adapter/Socket.php:253

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

【问题讨论】:

  • 我最终创建了自己的类来实现 Zend\Http\Client\Adapter\AdapterInterface,它使用 URLFetch 通过使用通常的 fopen 打开一个 URL 和流上下文来发送 POST 请求。虽然这可行,但我不确定这是最好的方法。如果可能,更愿意使用框架功能。
  • 我认为你的防火墙有问题看到这个答案stackoverflow.com/a/39590519/2652524
  • @GujaratSantana 我在两年多前问过这个问题,并找到了我之前评论中描述的解决方法。但这绝对不是防火墙问题 - 请注意错误消息是不同的,而且我的 Zend\Http\Client\Adapter\AdapterInterface 的自定义实现也有效。此外,代码部署在 Google AppEngine 中,开发人员无法控制防火墙。
  • 好的,很高兴知道

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


【解决方案1】:

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

这不会向您收取任何费用(除非您超出免费配额),但应该可以消除错误。

【讨论】:

  • 为此项目启用了计费。还有一个级别 - 让应用程序付费,但我认为这不会有任何区别。
  • 多一层是什么意思?我说的是 App Engine 计费。
  • 抱歉,我对 App Engine 文档中的措辞感到困惑,这些措辞有时指的是“启用计费”,有时指的是“付费应用程序”。计费肯定是启用的,因为我需要一个云 SQL 数据库,而且我确实看到了一些费用。
【解决方案2】:

从评论中提升了这一点-我最终创建了自己的类来实现Zend\Http\Client\Adapter\AdapterInterface,该类使用URLFetch,方法是使用带有流上下文的通常fopen打开一个URL来发送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
                );
            }
        }
    }

}

【讨论】:

    【解决方案3】:
    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;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-01-06
      • 1970-01-01
      • 2016-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多