我制作了一个简单的脚本,在tumblr上发布图片。 一切都很好,但在我改变主机提供商(我的新主机有限且价格低廉)之后,我发现了一些性能问题。
现在,在调试脚本并联系tumblr api服务台后,我遇到了问题:
有3个功能:
function oauth_gen($method, $url, $iparams, &$headers) {
$iparams['oauth_consumer_key'] = CONSUMER_KEY;
$iparams['oauth_nonce'] = strval(time());
$iparams['oauth_signature_method'] = 'HMAC-SHA1';
$iparams['oauth_timestamp'] = strval(time());
$iparams['oauth_token'] = OAUTH_TOKEN;
$iparams['oauth_version'] = '1.0';
$iparams['oauth_signature'] = oauth_sig($method, $url, $iparams);
$oauth_header = array();
foreach($iparams as $key => $value) {
if (strpos($key, "oauth") !== false) {
$oauth_header []= $key ."=".$value;
}
}
$str = print_r($iparams, true);
file_put_contents('data1-1.txt', $str);
$oauth_header = "OAuth ". implode(",", $oauth_header);
$headers["Authorization"] = $oauth_header;
}
function oauth_sig($method, $uri, $params) {
$parts []= $method;
$parts []= rawurlencode($uri);
$iparams = array();
ksort($params);
foreach($params as $key => $data) {
if(is_array($data)) {
$count = 0;
foreach($data as $val) {
$n = $key . "[". $count . "]";
$iparams []= $n . "=" . rawurlencode($val);
//$iparams []= $n . "=" . $val;
$count++;
}
} else {
$iparams[]= rawurlencode($key) . "=" .rawurlencode($data);
}
}
//debug($iparams,"iparams");
$str = print_r($iparams, true);
file_put_contents('data-1.txt', $str);
//$size = filesize('data.txt');
$parts []= rawurlencode(implode("&", $iparams));
//debug($parts,"parts");
//die();
$sig = implode("&", $parts);
return base64_encode(hash_hmac('sha1', $sig, CONSUMER_SECRET."&". OAUTH_SECRET, true));
}
以上这两个函数来自一个在线功能示例,它们一直运行良好。
这是我用来调用API和oAuth的函数:
function posta_array($files,$queue,$tags,$caption,$link,$blog){
$datArr = array();
$photoset_layout = "";
foreach ($files as $sing_file){
$dataArr [] = file_get_contents($sing_file);
$photoset_layout .= "1";
}
$headers = array("Host" => "http://api.tumblr.com/", "Content-type" => "application/x-www-form-urlencoded", "Expect" => "");
$params = array(
"data" => $dataArr,
"type" => "photo",
"state" => $queue,
"tags"=>$tags,
"caption"=>$caption,
"photoset_layout" => $photoset_layout,
"link"=>str_replace("_","",$link)
);
debug($headers,"head");
oauth_gen("POST", "http://api.tumblr.com/v2/blog/$blog/post", $params, $headers);
debug($headers,"head 2");
$ch = curl_init();
curl_setopt($ch, CURLOPT_USERAGENT, "Tumblr v1.0");
curl_setopt($ch, CURLOPT_URL, "http://api.tumblr.com/v2/blog/$blog/post");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: " . $headers['Authorization'],
"Content-type: " . $headers["Content-type"],
"Expect: ")
);
$params = http_build_query($params);
$str = print_r($params, true);
file_put_contents('data_curl1.txt', $str);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($ch);
debug($response,"response");
return $response;
}
这是有问题的功能,我试着解释一下:
我调用了oauth_gen
将参数数组传递给它,oauth_gen
创建了我后来在这里使用的oauth标头:"Authorization: " . $headers['Authorization'],
。
正如我所说,一切顺利,直到我试图发布6个文件的gif photoset,总共6Mb(tumblr允许每个文件2Mb,总共10Mb)。
PHP耗尽内存并返回错误,这里启动我的调试,一段时间后我联系了tumblr api帮助台,他们以这种方式回答:
您不应该将文件包含在用于的参数中 生成oauth签名。有关如何完成此操作的示例, 结帐我们的官方API客户之一。
这会改变一切。直到现在,我将整个参数数组传递给oauth_gen,调用oauth_sig,将所有内容原始编码到数组中(包含gif文件的二进制字符串),大约1Mb的二进制文件的结果变为至少3Mb的rawurlencoded字符串。
这就是我遇到记忆问题的原因。很好,所以,正如帮助台所说,我已经用这种方式改变了对oauth_gen的调用:
$new_array = array();
oauth_gen("POST", "http://api.tumblr.com/v2/blog/$blog/post", $new_array, $headers);
接缝是合法的,我传递了一个新的数组到函数,然后函数生成oAuth,标题被传回,我可以将它们用于发布调用,结果是:
{"meta":{"status":401,"msg":"Unauthorized"},"response":[]}
要求更多tumblr api帮助台只能链接到他们的文档和他们的" tumblr php客户端"这是我无法使用的,所以它不是一个选择。
有没有人有oAuth的经验,可以解释一下我做错了什么?据我所知,诀窍是oauth_sig创建的加密数据,但我无法弄清楚如何继续。
我真的很想了解oauth,但是我更多地了解它并且更多地了解了tumblr helpdsek接缝对我来说,但是...解决方案不起作用,只有当我让oauth功能运行时才有效加密整个数据阵列(包含图像和所有内容),但我可以理解这是错误的......帮助我。
更新1
我今天尝试过新的东西,首先我创建了空数组,然后通过引用oauth_gen
传递,并且只有在生成签名后,我才将所有其他字段添加到同一个数组中关于帖子本身,但结果是一样的。
更新2 在这里阅读:http://oauth.net/core/1.0a/#signing_process 似乎请求的参数必须全部用于签名,但这并不完全清楚(如果有人能更好地解释它,我真的很感激)。 这很奇怪,因为如果它是真的,那就违反了Tumblr服务台的话,如果不是这样,那么整个过程就会有一点混乱。 顺便说一句,在这个时候,我的格斗在同一点上敲响了。
答案 0 :(得分:4)
在挖掘问题几个小时后,调试,检查tumblr api和api客户端,注册测试帐户并尝试发布一些图像。好消息是我最终想出了一个解决方案。它不仅仅使用原生CURL,您需要guzzle和OAuth库来签署请求。
Tumblr伙伴们对签署请求是正确的。您无需传递图像数据即可对请求进行签名。如果你查看他们的官方图书馆,你可以看到; https://github.com/tumblr/tumblr.php/blob/master/lib/Tumblr/API/RequestHandler.php#L85
我试图解决本机CURL库的问题,但遗憾的是我没有成功,要么我以错误的方式签署请求,要么丢失了请求标题,数据等中的内容。我实际上并不知道,Tumblr api非常不好告诉你你做错了什么。
所以我欺骗了一点并开始阅读Tumblr api客户端代码,我想出了一个解决方案。
我们先走了,首先你需要两个包。
$ composer require "eher/oauth:1.0.*"
$ composer require "guzzle/guzzle:>=3.1.0,<4"
然后是PHP代码,只需定义你的密钥,令牌,秘密等等。那么它应该是好的。
由于签名请求不包含图片数据,因此不超过内存限制。在签署请求之后,实际上我们没有将文件的内容放入我们的post数据数组中。我们正在使用gu addPostFiles
方法,它负责POST请求的文件添加,为你做脏工作。这是我的结果;
string(70) "{"meta":{"status":201,"msg":"Created"},"response":{"id":143679527674}}"
这是网址;
http://blog-transparentcoffeebouquet.tumblr.com/
<?php
ini_set('memory_limit', '64M');
define("CONSUMER_KEY", "");
define("CONSUMER_SECRET", "");
define("OAUTH_TOKEN", "");
define("OAUTH_SECRET", "");
function request($options,$blog) {
// Take off the data param, we'll add it back after signing
$files = isset($options['data']) ? $options['data'] : false;
unset($options['data']);
$url = "https://api.tumblr.com/v2/blog/$blog/post";
$client = new \Guzzle\Http\Client(null, array(
'redirect.disable' => true
));
$consumer = new \Eher\OAuth\Consumer(CONSUMER_KEY, CONSUMER_SECRET);
$token = new \Eher\OAuth\Token(OAUTH_TOKEN, OAUTH_SECRET);
$oauth = \Eher\OAuth\Request::from_consumer_and_token(
$consumer,
$token,
"POST",
$url,
$options
);
$oauth->sign_request(new \Eher\OAuth\HmacSha1(), $consumer, $token);
$authHeader = $oauth->to_header();
$pieces = explode(' ', $authHeader, 2);
$authString = $pieces[1];
// POST requests get the params in the body, with the files added
// and as multipart if appropriate
/** @var \Guzzle\Http\Message\RequestInterface $request */
$request = $client->post($url, null, $options);
$request->addHeader('Authorization', $authString);
if ($files) {
if (is_array($files)) {
$collection = array();
foreach ($files as $idx => $f) {
$collection["data[$idx]"] = $f;
}
$request->addPostFiles($collection);
} else {
$request->addPostFiles(array('data' => $files));
}
}
$request->setHeader('User-Agent', 'tumblr.php/0.1.2');
// Guzzle throws errors, but we collapse them and just grab the
// response, since we deal with this at the \Tumblr\Client level
try {
$response = $request->send();
} catch (\Guzzle\Http\Exception\BadResponseException $e) {
$response = $request->getResponse();
}
// Construct the object that the Client expects to see, and return it
$obj = new \stdClass;
$obj->status = $response->getStatusCode();
$obj->body = $response->getBody();
$obj->headers = $response->getHeaders()->toArray();
return $obj;
}
$files = [
"/photo/1.jpg",
"/photo/2.jpg",
"/photo/3.png",
"/photo/4.jpg",
"/photo/1.jpg",
"/photo/2.jpg",
"/photo/3.png",
"/photo/4.jpg",
"/photo/1.jpg",
"/photo/2.jpg",
];
$params = array(
"type" => "photo",
"state" => "published",
"tags"=> [],
"caption"=>"caption",
"link"=>str_replace("_","","http://stackoverflow.com/questions/36747697/oauth-signature-creation-issue-with-php-posting-photoset-to-tumblr"),
"data" => $files,
);
$response = request($params, "blog-transparentcoffeebouquet.tumblr.com");
var_dump($response->body->__toString());