Я сделал простой скрипт, который размещает изображения на 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)); }
эти 2 функции выше приведены из онлайн-функционального примера, они всегда отлично работали.
это функция, которую я использую для вызова 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'],
"Authorization: " . $headers['Authorization'],
Как я уже сказал, все работает гладко, пока я не попытаюсь опубликовать gif-фотосет из 6 файлов на общую сумму 6 Мб (tumblr разрешает 2 Мб каждого файла и 10 Мб всего).
PHP заканчивается из памяти и возвращает ошибку, здесь начинается моя отладка, через некоторое время я связался с службой поддержки tumblr api, и они отвечают следующим образом:
Вам не нужно включать файлы в параметры, используемые для генерации сигнатуры oauth. Для примера того, как это делается, обратитесь к одному из наших официальных клиентов API.
Это меняет все. До сих пор я передавал весь массив параметров в oauth_gen, который, вызывая oauth_sig, будет помещать все в массив (двоичные строки gif-файлов inlcuded), в результате двоичный файл размером около 1 Мб становится не менее 3 МБ 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 helpdesk, приводит только к большему количеству ссылок на их документацию и их «tumblr php client», которые я не могу использовать, поэтому это не вариант.
Кто-нибудь имеет опыт работы с 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, но, к сожалению, я не был успешным, либо я неправильно подписывал запрос, либо пропустил что-то в заголовке запроса, данных и т. Д. На самом деле я не знаю, Tumblr api действительно плохой сообщая вам, что вы делаете неправильно.
Поэтому я немного обманул и начал читать клиентский код Tumblr api, и я придумал решение.
Здесь мы идем, сначала вам нужны два пакета.
$ composer require "eher/oauth:1.0.*" $ composer require "guzzle/guzzle:>=3.1.0,<4"
А затем PHP-код, просто определите свои ключи, токены, секреты и т. Д. Тогда должно быть хорошо идти.
Поскольку запрос подписи не включает данные изображения, он не превышает предела памяти. После подписания запроса на самом деле мы не получаем содержимое файлов в наш массив данных сообщений. Мы используем метод addPostFiles
, который заботится о добавлении файла к запросу 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());
не<?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());