如何使用php身份验证脚本作为CouchDB的代理,同时仍然保持完整的REST API功能?
How do I use a php authentication script as proxy to CouchDB and still maintain full REST API functionality?
我最近成功安装了CouchDB 1.2.1版本,作为测试,我可以使用以下Apache在CentOS 6中重写访问它:
RewriteRule couchdb/(.*)$ http://127.0.0.1:5984/$1 [QSA,P]
我有一个PHP认证类,我在一个本地开发的API中使用它来支持我的移动应用程序。我的API使用包含在URL中的HMAC签名接受并验证每个请求,如下所示:
https://api.domain.com/endpoint/?timestamp=[timestamp]&signature=[signature]&id=[id]...etc
每个端点都有相应的脚本,确保在处理之前检查正确的签名。
理想情况下,我想用某种PHP脚本有效地替换上述反向代理重写规则,该脚本将充当CouchDB实例的看门人/网关,利用我的身份验证类,同时仍然保留所有本地CouchDB REST API功能,包括但不限于用户的复制和cookie身份验证(以上仅用于API身份验证)。这能做到吗?我已经尝试使用如下修改的这个解决方案,但是虽然它实际上会回踢有效的JSON响应,但复制失败,并且我怀疑其他方面(如用户身份验证)也会失败:
<?php
require_once('CouchDBProxy.php');
require_once("common.php");
//set some vars
$resource = $_GET['resource'];
$id = $_GET['appid'];
$timestamp = $_GET['timestamp'];
$signature = $_GET['signature'];
//use common class for validating sig
if ( Access::validSignature( $id, $timestamp, $signature ) ) {
$proxy = new CouchDBProxy('127.0.0.1', '5984');
$proxy->proxy('/'.$resource);
}
?>
<?php
//COUCHDB_PROXY.PHP
class CouchDBProxy
{
public $host;
public $port;
public $timeout = 10;
/**
* Initialize the proxy service
*
* @param string $host the host where the requests should be forwarded
* @param string $port the port on the host to use
* @author Adam Venturella
*/
public function __construct($host, $port)
{
$this->host = $host;
$this->port = $port;
}
/**
* Begin proxying
*
* @return void
* @author Adam Venturella
*/
public function proxy($resource)
{
$verb = strtolower($_SERVER['REQUEST_METHOD']);
$command = null;
switch($verb)
{
case 'get':
$command = $this->proxy_get($resource);
break;
case 'post':
$command = $this->proxy_post($resource);
break;
case 'put':
$command = $this->proxy_put($resource);
break;
case 'delete':
$command = $this->proxy_delete($resource);
break;
case 'head':
$command = $this->proxy_head($resource);
break;
}
if($command)
{
curl_exec($command);
curl_close($command);
}
}
/**
* Handle GET requests
*
* @return void
* @author Adam Venturella
*/
private function proxy_get($resource)
{
return $this->request($resource);
}
/**
* Handle HEAD requests
*
* @return void
* @author Adam Venturella
*/
private function proxy_head($resource)
{
$command = $this->request($resource);
curl_setopt( $command, CURLOPT_NOBODY, true);
return $command;
}
/**
* Handle POST requests
*
* @return void
* @author Adam Venturella
*/
private function proxy_post($resource)
{
$command = $this->request($resource);
$data = file_get_contents("php://input");
curl_setopt($command, CURLOPT_POST, true);
curl_setopt($command, CURLOPT_POSTFIELDS, $data);
return $command;
}
/**
* Handle DELETE Requests
*
* @return void
* @author Adam Venturella
*/
private function proxy_delete($resource)
{
$command = $this->request($resource);
curl_setopt($command, CURLOPT_CUSTOMREQUEST, 'DELETE');
return $command;
}
/**
* Handle PUT requests
*
* @return void
* @author Adam Venturella
*/
private function proxy_put($resource)
{
$command = $this->request($resource);
$data = file_get_contents("php://input");
curl_setopt($command, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($command, CURLOPT_POSTFIELDS, $data);
return $command;
}
/**
* Build the basic request
*
* @return void
* @author Adam Venturella
*/
private function request($resource)
{
$action = $_SERVER['REQUEST_METHOD'];
$uri = $resource;
// $uri = $_SERVER['REQUEST_URI'];
$params = null;
//added from http://stackoverflow.com/questions/2916232/call-to-undefined-function-apache-request-headers
if( !function_exists('apache_request_headers') ) {
function apache_request_headers() {
$arh = array();
$rx_http = '/'AHTTP_/';
foreach($_SERVER as $key => $val) {
if( preg_match($rx_http, $key) ) {
$arh_key = preg_replace($rx_http, '', $key);
$rx_matches = array();
// do some nasty string manipulations to restore the original letter case
// this should work in most cases
$rx_matches = explode('_', $arh_key);
if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
foreach($rx_matches as $ak_key => $ak_val) $rx_matches[$ak_key] = ucfirst($ak_val);
$arh_key = implode('-', $rx_matches);
}
$arh[$arh_key] = $val;
}
}
return( $arh );
}
}
$headers = apache_request_headers();
$context = array();
$context[] = 'Host: '.$this->host.':'.$this->port;
$context[] = 'X-Forwarded-For: '.$_SERVER['REMOTE_ADDR'];
$context[] = 'X-Forwarded-Host: '.$_SERVER['HTTP_HOST'];
$context[] = 'X-Forwarded-Server: '.$_SERVER['SERVER_NAME'];
foreach($headers as $key=>$value)
{
if(strtolower($key) != 'host')
{
$context[] = $key.': '.$value;
}
}
$command = curl_init();
curl_setopt( $command, CURLOPT_HTTPHEADER, $context);
curl_setopt( $command, CURLOPT_URL, "http://".$this->host.':'.$this->port.$uri);
curl_setopt( $command, CURLOPT_BINARYTRANSFER, true );
curl_setopt( $command, CURLOPT_TIMEOUT, $this->timeout );
curl_setopt( $command, CURLOPT_HEADERFUNCTION, array($this,'processResponseHeaders'));
curl_setopt( $command, CURLOPT_WRITEFUNCTION, array($this,'processResponseBody'));
return $command;
}
/**
* Process the response body
*
* @param cURL $command reference to the curl command used to generate this response
* @param string $data the response body
* @return void
* @author Adam Venturella
*/
private function processResponseBody(&$command, $data)
{
$bytes = strlen($data);
echo $data;
return $bytes;
}
/**
* Process the response headers
*
* @param cURL $command reference to the curl command used to generate this response
* @param string $header current header in the response
* @return void
* @author Adam Venturella
*/
private function processResponseHeaders(&$command, $header)
{
$bytes = strlen($header);
// cURL handles chunked decoding for us, so a response from
// this proxy will never be chunked
if ($header !== "'r'n" && strpos($header, 'chunked') === false)
{
header(rtrim($header));
}
return $bytes;
}
}
?>
我已经在这几天,我似乎不能使它工作,所以我扔掉它的帮助要么得到php代理脚本的权利,或帮助确定一个替代的方法。
我猜复制(例如_changes提要)使用长存活请求和分块传输编码,而您的PHP代理不支持。
相关文章:
- 在谷歌api v3中使用地理自动完成功能获取邮政编码
- 如何修改此功能以获得最受欢迎的视频?(YouTube API v3)
- JavaScript 的全新功能,使用 Google Maps API v3 w/ custom fitbounds (
- 这里是 JavaScript API 3.x - 自动完成功能
- 仅通过 Google 地图 API 自动完成功能获取城市名称
- 谷歌地图API - 这条线的含义/功能是什么
- 如何在 Google 地点 API 中使用附近的搜索功能查找地点详细信息
- 谷歌地图API V3与图标类型和选择功能
- 向 Google Maps API 添加其他功能
- 地理位置 api 中是否有任何功能,例如 是 地理位置允许 or 是 地理位置允许永远.
- 谷歌地图API v3:是否有任何功能可以检查坐标是否在省或国家/地区内
- 如何将标准API功能添加到jQuery插件中
- 用于Office的Javascript API:如何手动触发MS Office'的自动套用格式功能
- 调用自定义API方法的功能
- 使用Laravel作为API存储数据,并带有ajax功能
- 谷歌地图API功能启用
- 谷歌地图api v3:为编辑后的多边形添加自定义撤消/重做功能
- 在集会web api中是否有查询特定日期的功能
- 谷歌地图地理编码API,功能从API缺少在他们的JS API (?)
- 如何获得html5文件API功能与浏览器拖动图像