Я сделал простой скрипт, который размещает изображения на 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'],
,
Как я уже говорил, все работает гладко, пока я не попытался опубликовать gif-фотосет из 6 файлов на общую сумму 6 МБ (tumblr разрешает 2 МБ каждый файл и всего 10 МБ).
PHP не хватает памяти и возвращает ошибку, здесь он начинает мою отладку, через некоторое время я связался со службой поддержки Tumblr API, и они отвечают следующим образом:
Вам не нужно включать файлы в параметры, используемые для
генерирование подписи oauth. Для примера того, как это делается,
Оформить заказ одного из наших официальных клиентов API.
Это меняет все. До сих пор я передавал весь массив параметров в oauth_gen, который, вызывая oauth_sig, будет кодировать все в массив (включая двоичные строки gif-файлов), в результате двоичный файл размером около 1 МБ становится не менее 3 МБ в rawurlencoded строка.
и именно поэтому у меня были проблемы с памятью. Хорошо, так что, как говорят сотрудники службы поддержки, я изменил вызов oauth_gen следующим образом:
$new_array = array();
oauth_gen("POST", "http://api.tumblr.com/v2/blog/$blog/post", $new_array, $headers);
мне кажется, что швы законные, я передал новый массив функции, затем функция генерирует oAuth, заголовки передаются обратно, и я могу использовать их в вызове posting, результат был:
{"meta":{"status":401,"msg":"Unauthorized"},"response":[]}
просьба к tumblr api helpdesk приводит только к большему количеству ссылок на их документацию и их «клиент tumblr php», которые я не могу использовать, так что это не вариант.
Кто-нибудь имеет опыт работы с oAuth и может объяснить, что я делаю не так? Насколько я понимаю, дело в зашифрованных данных, которые создает oauth_sig, но я не могу понять, как действовать дальше.
Я действительно хочу понять oauth, но больше я читаю об этом, и больше tumblr helpdsek кажется мне правильным, но … решение не работает, и работает, только если я позволю функции oauth зашифровать весь массив данных (с изображениями и всем), но я могу понять, что это неправильно … помогите мне.
ОБНОВЛЕНИЕ 1
Сегодня я попробовал что-то новое, сначала я создал пустой массив, а затем передал ссылку на oauth_gen
и только после генерации подписи я добавил в тот же массив все остальные поля, касающиеся самого сообщения, но результат тот же.
ОБНОВЛЕНИЕ 2
читая здесь: http://oauth.net/core/1.0a/#signing_process
Кажется, что параметры запроса должны все использоваться для подписи, но это не совсем ясно (если кто-то мог бы объяснить это лучше, я действительно ценю).
это странно, потому что, если это правда, это идет вразрез со словами службы поддержки Tumblr, в то время как если это не так, во всем процессе возникает небольшая путаница.
Кстати, в это время я все же ударил в ту же точку.
Поработав пару часов в проблеме, отладке, просмотре tumblr api и api client, регистрации тестовой учетной записи и попытке опубликовать несколько изображений. Хорошая новость заключается в том, что я наконец-то нашел решение. Он не использует только собственный CURL, для подписи запросов вам нужны библиотека и библиотека OAuth.
Ребята Tumblr правы в подписании запроса. Вам не нужно передавать данные изображения, чтобы подписать запрос. Если вы проверите их официальную библиотеку, вы можете увидеть; https://github.com/tumblr/tumblr.php/blob/master/lib/Tumblr/API/RequestHandler.php#L85
Я пытался решить проблему с родной библиотекой CURL, но, к сожалению, у меня ничего не получилось, либо я неправильно подписывал запрос, либо что-то пропустил в заголовке запроса, данных и т. Д. На самом деле я не знаю, API Tumblr действительно плох при информировании вас о том, что вы делаете неправильно.
Поэтому я немного обманул и начал читать клиентский код Tumblr api, и я нашел решение.
Итак, сначала вам нужно два пакета.
$ composer require "eher/oauth:1.0.*"$ composer require "guzzle/guzzle:>=3.1.0,<4"
А затем код PHP, просто определите свои ключи, токены, секреты и т. Д. Тогда все должно быть хорошо.
Поскольку запрос на подпись не включает в себя данные изображения, он не превышает лимит памяти. После подписания запроса мы фактически не получаем содержимое файлов в наш массив данных post. Мы используем addPostFiles
Метод guzzle, который заботится о добавлении файлов в POST-запрос, делает грязную работу за вас. И вот результат для меня;
string(70) "{"meta":{"status":201,"msg":"Created"},"response":{"id":143679527674}}"
А вот и URL;
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());
Других решений пока нет …