PHP 的 oAuth 签名创建问题(将照片集发布到 Tumblr) [英] oAuth signature creation issue with PHP (posting photoset to Tumblr)

查看:24
本文介绍了PHP 的 oAuth 签名创建问题(将照片集发布到 Tumblr)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我制作了一个简单的脚本,可以在 tumblr 上发布图片.一切都很好,但我在更换主机提供商后立即发现了一些性能问题(我的新主机有限且更便宜).

I've made a simple script that posts images on tumblr. everything is fine, but I've noticed some performance issues right after I've changed the host provider (my new host is limited and cheaper).

现在,在调试脚本并联系 tumblr api 服务台后,我遇到了一个问题:

now, after debugging the script and after contacting the tumblr api helpdesk, I'm stuck on a problem:

有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));
}

以上这两个函数来自一个在线函数示例,它们一直运行良好.

these 2 functions above comes from an online functional example, they have always worked fine.

这是我用来调用 API 和 oAuth 的函数:

this is the function I use to call the APIs and the 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;

}

这个函数有问题,我试着解释一下:

this is the function with some problems, I try to explain:

我调用了将参数数组传递给它的 oauth_genoauth_gen 创建了我后来在这里使用的 oauth 标头:"Authorization:".$headers['授权'],.

I called the oauth_gen passing the parameters array to it, the oauth_gen creates the oauth header that I later used here: "Authorization: " . $headers['Authorization'],.

正如我所说,一切都很顺利,直到我尝试发布 6 个文件的 gif 照片集,总共 6Mb(tumblr 允许每个文件 2Mb,总共 10Mb).

As I stated, everything is working smoothly, until I have tried to post a gif photoset of 6 files for a total of 6Mb (tumblr permit 2Mb each file and 10Mb total).

PHP 内存不足并返回错误,在这里它开始我的调试,一段时间后我联系了 tumblr api 帮助台,他们以这种方式回答:

PHP runs out of memory and return an error, here it starts my debugging, after a while I contacted the tumblr api helpdesk, and they answer in this way:

您不需要在用于的参数中包含文件生成 oauth 签名.有关如何完成此操作的示例,查看我们的官方 API 客户端之一.

You shouldn't need to include the files in the parameters used for generating the oauth signature. For an example of how this is done, checkout one of our official API clients.

这改变了一切.直到现在,我将整个参数数组传递给 oauth_gen,它调用 oauth_sig 将所有内容原始编码到数组中(包括 gif 文件的二进制字符串),结果大约 1Mb 的二进制文件变成至少 3Mb 的原始编码字符串.

This changes everything. Untill now, I passed the entire parameters array to the oauth_gen, which, calling the oauth_sig, will rawencode everything into the array (binary strings of gif files inlcuded), with a result of a binary file of about 1Mb becomes at least 3Mb of rawurlencoded string.

这就是我有记忆问题的原因.很好,所以,正如服务台所说,我已经以这种方式更改了对 oauth_gen 的调用:

and that's why I had memory issues. Nice, so, as the helpdesk say, I've changed the call to the oauth_gen in this way:

$new_array = array();
oauth_gen("POST", "http://api.tumblr.com/v2/blog/$blog/post", $new_array, $headers); 

对我来说是合法的,我将一个新数组传递给函数,然后函数生成 oAuth,将标头传回,我可以将它们用于发布调用,结果是:

seams legit to me, I passed a new array to the function, the function then generate the oAuth, the headers are passed back and I can use them into the posting call, the result was:

{"meta":{"status":401,"msg":"Unauthorized"},"response":[]}

向 tumblr api 服务台询问更多信息只会导致更多指向他们的文档和我无法使用的tumblr php 客户端"的链接,因此它不是一个选项.

asking more to tumblr api helpdesk leads only to more links to their documentation and their "tumblr php client" which I can't use, so it isn't a option.

有没有人有 oAuth 的经验并且可以解释我做错了什么?据我了解,诀窍在于 oauth_sig 创建的加密数据,但我不知道如何进行.

Does anyone has experience with oAuth and can explain me what I'm doing wrong? as far as I understand, the trick is into the encrypted data the oauth_sig create, but I can't figure out how to proceed.

我真的很想了解 oauth,但我读了更多有关它的信息,而且 tumblr helpdsek 对我来说更合适,但是……该解决方案不起作用,只有当我让 oauth 函数加密整个数据数组(包括图像和所有内容),但我可以理解这是错误的...帮助我.

I really want to understand the oauth, but more I read about it and more the tumblr helpdsek seams right to me, but... the solution doesn't work, and works only if I let the oauth function to encrypt the entire data array (with the images and everything) but I can understand that this is wrong... help me.

更新 1我今天尝试了一个新东西,首先我创建了空数组,然后通过引用传递给 oauth_gen 并且只有在生成签名之后,我才将所有其他字段添加到同一个数组中帖子本身,但结果是一样的.

UPDATE 1 I've tried a new thing today, first I created the empty array, then passed by reference to the oauth_genand only after generating the signature, I've added to the same array all the other fields about the post itself, but the result is the same.

更新 2在这里阅读:http://oauth.net/core/1.0a/#signing_process似乎请求的参数都必须用于签名,但这并不完全清楚(如果有人能解释得更好,我真的很感激).这很奇怪,因为如果是真的,就违背了 Tumblr 服务台的说法,如果不是真的,整个过程就会有点混乱.顺便说一句,此时,我对同一点感到震惊.

UPDATE 2 reading here: http://oauth.net/core/1.0a/#signing_process seems that the parameters of the request must all be used for the signature, but this is not totally clear (if someone could explain it better, I really appreciate). this is weird, because if it's true, it go against the words of the Tumblr help desk, while if it's not true, there is a little confusion in the whole process. by the way, at this time, I'm stile struck in the same point.

推荐答案

在对问题进行了几个小时的挖掘、调试、审查 tumblr api 和 api 客户端后,注册了一个测试帐户并尝试发布一些图像.好消息是我终于想出了一个解决方案.它不仅仅使用本机 CURL,您需要大量使用 OAuth 库来签署请求.

After digging couple of hours into the issue, debugging, reviewing tumblr api and api client, registering a test account and trying to post some images. The good news is finally I come up with a solution. It is not using a native CURL only, you need guzzle and an OAuth library to sign the requests.

Tumblr 的人对签署请求是正确的.您不需要传递图像数据来签署请求.如果您查看他们的官方图书馆,您可以看到;https://github.com/tumblr/tumblr.php/blob/master/lib/Tumblr/API/RequestHandler.php#L85

Tumblr guys are correct about signing the request. You don't need to pass image data to sign the request. If you check their official library you can see; https://github.com/tumblr/tumblr.php/blob/master/lib/Tumblr/API/RequestHandler.php#L85

我尝试使用本机 CURL 库解决该问题,但不幸的是我没有成功,要么我以错误的方式签署请求,要么在请求标头、数据等中丢失了某些内容.我实际上不知道,Tumblr api在告诉你你做错了什么方面真的很糟糕.

I tried to fix the issue with native CURL library but unfortunately I was not successful, either I was signing the request in a wrong way or missing something in the request header, data etc. I don't know actually, Tumblr api is really bad at informing you what you are doing wrong.

于是我作弊了一点,开始阅读Tumblr api客户端代码,并想出了一个解决方案.

So I cheated a little bit and start to read Tumblr api client code, and I come up with a solution.

我们开始,首先你需要两个包.

Here we go, first you need two packages.

$ composer require "eher/oauth:1.0.*"
$ composer require "guzzle/guzzle:>=3.1.0,<4"

然后是 PHP 代码,只需定义您的密钥、令牌、秘密等.然后就可以了.

And then the PHP code, just define your keys, tokens, secrets etc. Then it should be good to go.

由于签名请求不包含图片数据,所以不超过内存限制.实际上,在签署请求后,我们并没有将文件的内容放入我们的 post 数据数组中.我们正在使用 guzzle 的 addPostFiles 方法,它负责将文件添加到 POST 请求,为您完成肮脏的工作.这是我的结果;

Since the signing request does not include picture data, it is not exceeding memory limit. After signing the request actually we are not getting the contents of the files into our post data array. We are using addPostFiles method of guzzle, which takes care of file addition to POST request, does the dirty work for you. And here is the result for me;

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());

这篇关于PHP 的 oAuth 签名创建问题(将照片集发布到 Tumblr)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆