我试图在谷歌应用引擎上使用PHP和Zend框架实现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)' in/基地/数据/home/…/后端:v1.375711862873219029/供应商/zendframework/zend-http/Zend/Http/客户/适配器/Socket.php: 253
我知道App Engine不允许套接字连接,并为http和https提供urlFetch包装,但我如何告诉Zend框架使用这种传输?
尝试启用计费功能。据我所知,套接字仅在付费应用程序中启用。
这不会向您收取任何费用(除非您超过了免费配额),但应该可以消除错误。
从评论中提升了这一点-我最终制作了自己的类实现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
);
}
}
}
}
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;
}