php-curl封裝[避免上傳文件二義性Bug]

由於php的curl在curl_setopt($curl, CURLOPT_POSTFIELDS, xxx)時, 當xxx爲數組時, 如果值的第一個字符是@, 則認爲是文件上傳, 當同時需要上傳文件, 也需要提交可能首字符爲@的其他普通數據時, 存在衝突. 因此, 在api_common.php中的post數據的設置進行了封裝


<?php
/**
 * php-curl庫封裝
 * author: selfimpr
 * blog: http://blog.csdn.net/lgg201
 * mail: [email protected]
 */

define('API_CURL_UPLOAD_FILE',							'__file');

#支持的請求方法
define('REQUEST_METHOD_GET',							'GET');
define('REQUEST_METHOD_POST',							'POST');
define('REQUEST_METHOD_HEAD',							'HEAD');

#請求行爲
define('REQUEST_BEHAVIOR_ALLOW_REDIRECT',				'allow_redirect');
define('REQUEST_BEHAVIOR_MAX_REDIRECT',					'max_redirect');
define('REQUEST_BEHAVIOR_USER_AGENT',					'user_agent');
define('REQUEST_BEHAVIOR_AUTOREFERER',					'autoreferer');
define('REQUEST_BEHAVIOR_UPLOAD',						'upload');
define('REQUEST_BEHAVIOR_CONNECTTIMEOUT',				'connecttimeout');
define('REQUEST_BEHAVIOR_DNS_CACHE_TIMEOUT',			'dns_cache_timeout');
define('REQUEST_BEHAVIOR_TIMEOUT',						'timeout');
define('REQUEST_BEHAVIOR_ENCODING',						'encoding');
define('REQUEST_BEHAVIOR_ERROR_HANDLER',				'error_handler');
define('REQUEST_BEHAVIORS',								'behaviors');
$GLOBALS[REQUEST_BEHAVIORS]	= array(
	REQUEST_BEHAVIOR_ALLOW_REDIRECT				=> TRUE, 
	REQUEST_BEHAVIOR_MAX_REDIRECT				=> 5, 
	REQUEST_BEHAVIOR_USER_AGENT					=> 'curl-lib', 
	REQUEST_BEHAVIOR_AUTOREFERER				=> TRUE, 
	REQUEST_BEHAVIOR_UPLOAD						=> FALSE, 
	REQUEST_BEHAVIOR_CONNECTTIMEOUT				=> 3, 
	REQUEST_BEHAVIOR_DNS_CACHE_TIMEOUT			=> 3600, 
	REQUEST_BEHAVIOR_TIMEOUT					=> 3, 
	REQUEST_BEHAVIOR_ENCODING					=> 'gzip', 
	REQUEST_BEHAVIOR_ERROR_HANDLER				=> '__default_curl_error_handler', 
);

define('MULTIPART_FORM_DATA_HEAD_FMT',				'Content-Type: multipart/form-data; boundary=----------------------------%s');
define('MULTIPART_FORM_DATA_BODY_STRING',			"------------------------------%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n");
define('MULTIPART_FORM_DATA_BODY_FILE',				"------------------------------%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n%s\r\n");
define('MULTIPART_FORM_DATA_BODY_END',				"------------------------------%s--\r\n\r\n");

#響應鍵值
define('RESP_CODE',									'resp_code');
define('RESP_BODY',									'resp_body');
define('RESP_HEADER',								'resp_header');

#HTTP 1xx狀態驗證
define('HTTP_1XX_RESP',								'/^HTTP\/1.[01] 1\d{2} \w+/');

#默認錯誤處理的錯誤消息
define('E_CURL_ERROR_FMT',								'curl "%s" error[%d]: %s');

#默認的curl錯誤處理
function __default_curl_error_handler($curl, $url, $errno, $errstr) {
	trigger_error(sprintf(E_CURL_ERROR_FMT, $url, $errno, $errstr), E_USER_ERROR);
}
#切換CURL請求方法
function __method_switch($curl, $method) {
	switch ( $method) {
		case REQUEST_METHOD_POST:
			__curl_setopt($curl, CURLOPT_POST, TRUE);
			break;
		case REQUEST_METHOD_HEAD:
			__curl_setopt($curl, CURLOPT_NOBODY, TRUE);
			break;
		case REQUEST_METHOD_GET:
			__curl_setopt($curl, CURLOPT_HTTPGET, TRUE);
			break;
		default:
			break;
	}
}
#設置默認頭信息
function __default_header_set($curl) {
	__curl_setopt($curl, CURLOPT_RETURNTRANSFER,			TRUE);
	__curl_setopt($curl, CURLOPT_HEADER,					TRUE);
	__curl_setopt($curl, CURLOPT_FOLLOWLOCATION,			(bool)curl_behavior(REQUEST_BEHAVIOR_ALLOW_REDIRECT));
	__curl_setopt($curl, CURLOPT_MAXREDIRS,					(int)curl_behavior(REQUEST_BEHAVIOR_MAX_REDIRECT));
	__curl_setopt($curl, CURLOPT_USERAGENT,					(string)curl_behavior(REQUEST_BEHAVIOR_USER_AGENT));
	__curl_setopt($curl, CURLOPT_AUTOREFERER,				(bool)curl_behavior(REQUEST_BEHAVIOR_AUTOREFERER));
	__curl_setopt($curl, CURLOPT_UPLOAD,					(bool)curl_behavior(REQUEST_BEHAVIOR_UPLOAD));
	__curl_setopt($curl, CURLOPT_CONNECTTIMEOUT,			(int)curl_behavior(REQUEST_BEHAVIOR_CONNECTTIMEOUT));
	__curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT,			(int)curl_behavior(REQUEST_BEHAVIOR_DNS_CACHE_TIMEOUT));
	__curl_setopt($curl, CURLOPT_TIMEOUT,					(int)curl_behavior(REQUEST_BEHAVIOR_TIMEOUT));
	__curl_setopt($curl, CURLOPT_ENCODING,					(string)curl_behavior(REQUEST_BEHAVIOR_ENCODING));
}
#設置用戶自定義頭信息
function __custom_header_set($curl, $headers = NULL) {
	if ( empty($headers) ) return ;
	if ( is_string($headers) ) 
		$headers	= explode("\r\n", $headers);
	#類型修復
	foreach ( $headers as &$header ) 
		if ( is_array($header) ) 
			$header	= sprintf('%s: %s', $header[0], $header[1]);
	__curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
#設置請求body
function __datas_set($curl, $datas = NULL) {
	if ( empty($datas) ) return ;
	if ( is_array($datas) ) {
		$custom_body		= FALSE;
		$uniqid				= uniqid();
		$custom_body_str	= '';
		foreach ( $datas as $name => $data ) {
			if ( is_array($data) && array_key_exists(API_CURL_UPLOAD_FILE, $data) ) {
				$file	= $data[API_CURL_UPLOAD_FILE];
				if ( file_exists($file) ) {
					$custom_body		= TRUE;
					$custom_body_str	.= sprintf(MULTIPART_FORM_DATA_BODY_FILE, 
										$uniqid, $name, 
										$file, file_get_contents($file));
				}
			} else {
				$custom_body_str		.= sprintf(MULTIPART_FORM_DATA_BODY_STRING, 
										$uniqid, $name, $data);
			}
		}
		if ( $custom_body ) {
			curl_setopt($curl, CURLOPT_HTTPHEADER, array(sprintf(MULTIPART_FORM_DATA_HEAD_FMT, $uniqid)));
			$datas				= $custom_body_str . sprintf(MULTIPART_FORM_DATA_BODY_END, $uniqid);
		}
	}
	__curl_setopt($curl, CURLOPT_POSTFIELDS, $datas);
}
#對curl_setopt的封裝
function __curl_setopt($curl, $optname, $optval) {
	curl_setopt($curl, $optname, $optval);
	__curl_error($curl);
}
#curl錯誤檢查處理
function __curl_error($curl) {
	if ( curl_errno($curl) ) {
		$url	= curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
		$errno	= curl_errno($curl);
		$errstr	= curl_error($curl);
		$errh	= curl_behavior(REQUEST_BEHAVIOR_ERROR_HANDLER);
		if ( function_exists($errh) )
			$errh($curl, $url, $errno, $errstr);
	}
}

#api默認行爲切換
function curl_behavior($names, $values = NULL) {
	if ( !is_string($names) && !is_array($names) ) return ;
	if ( !is_null($values) ) {
		if ( is_string($names) ) 
			$GLOBALS[REQUEST_BEHAVIORS][$names]	= $values;
		else if ( is_array($names) && !is_array($values) )
			foreach ( $names as $name )
				$GLOBALS[REQUEST_BEHAVIORS][$name]	= $values;
		else if ( is_array($names) && is_array($values) )
			foreach ( $names as $k => $name ) 
				$GLOBALS[REQUEST_BEHAVIORS][$name]	= $values[$k];
	}
	if ( is_string($names) ) {
		$return	= $GLOBALS[REQUEST_BEHAVIORS][$names];
	} else if ( is_array($names) ) {
		$return	= array();
		foreach ( $names as $name ) 
			$return[$name]	= array_key_exists($name, $GLOBALS[REQUEST_BEHAVIORS]) 
							? $GLOBALS[REQUEST_BEHAVIORS][$name]
							: NULL;
	}
	return $return;
}
#請求入口
function curl_request($url, $method, $datas = NULL, $headers = NULL) {
	$curl	= curl_init($url);
	__method_switch($curl, $method);
	__default_header_set($curl);
	__custom_header_set($curl, $headers);
	__datas_set($curl, $datas);
	$response	= curl_exec($curl);
	__curl_error($curl);
	$status_code	= curl_getinfo($curl, CURLINFO_HTTP_CODE);
	$components		= explode("\r\n\r\n", $response);
	$i				= -1;
	while ( ++ $i < count($components) ) 
		if ( !preg_match(HTTP_1XX_RESP, $components[$i]) ) break;
	$headers		= $components[$i];
	$body			= implode("\r\n\r\n", array_slice($components, $i + 1));
	return array(
		RESP_CODE	=> $status_code, 
		RESP_HEADER	=> $headers, 
		RESP_BODY	=> $body, 
	);
}
#GET請求
function curl_get($url, $headers = NULL) {
	return curl_request($url, REQUEST_METHOD_GET, NULL, $headers);
}
#POST請求
function curl_post($url, $datas = NULL, $headers = NULL) {
	return curl_request($url, REQUEST_METHOD_POST, $datas, $headers);
}
#HEAD請求
function curl_head($url, $headers = NULL) {
	return curl_request($url, REQUEST_METHOD_HEAD, NULL, $headers);
}
#構造上傳文件字段
function curl_post_file($file) {
	return array(
		API_CURL_UPLOAD_FILE	=> $file, 
	);
}
#讀取響應碼
function curl_resp_code($resp) {
	return $resp[RESP_CODE];
}
#讀取響應頭
function curl_resp_header($resp) {
	return $resp[RESP_HEADER];
}
#讀取響應體
function curl_resp_body($resp) {
	return $resp[RESP_BODY];
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章