我正在尝试使用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使用此传输?
答案 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
);
}
}
}
}