【问题标题】:How do I make a simple PHP API handler?如何制作一个简单的 PHP API 处理程序?
【发布时间】:2017-04-25 19:36:57
【问题描述】:

我使用 cURL 在 PHP 中编写了一个基本的 API 脚本 - 并在另一个 API 上成功使用了它的一个版本,这个版本专门用于处理 DigitalOcean 上的域 DNS 管理 - 我无法发送数据?

前奏...

我知道有一个 PHP 库可用,我不追求功能齐全或依赖关系臃肿的东西 - 只是在本地使用的小东西 主要是为了帮助我了解 RESTful API 的工作原理在实践中更好 - 一种教育练习

违规代码...

function basic_api_handle($key, $method, $URI, $data) {

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Authorization: Bearer '.$key,
        'Content-Type: application/json')
    );

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_URL, $URI);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

    $result = curl_exec($ch);
    if($result === false) error_log("API ERROR: Connection failure: $URI", 0);

    curl_close($ch);

    return json_decode($result, true);
}

var_dump(basic_api_handle($api_key, 'POST', 'https://api.digitalocean.com/v2/domains', array('name' => 'my-domain.tld', 'ip_address' => '1.2.3.4')));

这适用于 GET 请求,例如列出帐户上的域,但似乎无法发布/发送数据...这会导致“unprocessable_entity”和“名称不能为空” - 因为名称是不是空白并且格式正确(据我所知)它向我表明数据没有正确发送?

到目前为止的解决方案尝试...

我尝试过对数据进行 json 编码(见代码),而不是 json 编码、带有和不带有 json 编码的 url 编码以及各种其他选项,但都没有运气。

我在网上看到过一些关于 DigitalOcean API(和另一个)的完全相同问题的帖子,但没有人解释(除了放弃并使用库或其他影响)。

直接从终端使用 cURL 确实可以工作等,因此用于创建域的 API 没有任何问题。

据我了解,身份验证工作正常,一般设置工作正常,因为我可以列出帐户中的域,我只是不能 POST 或 PUT 新数据。我一直在使用API's documentation 并且看不到我做错了什么,也许是某种错误的编码?

任何帮助将不胜感激! :)

编辑:大量工作和研究之后,即使是其他简单的 API 处理程序也无法与 Digital Ocean 一起使用(例如 https://github.com/ledfusion/php-rest-curl) - 这个 API 是否有特别需要的东西,或者我是否缺少关于 API 的基本知识?

【问题讨论】:

  • 也许你错过了这个:curl_setopt($ch, CURLOPT_POST, true);
  • 我认为对于这样的 API,您不需要将方法从 POST 更改为 GET 和 PUT 等其他方法
  • 嘿!我只是想让你知道你不会发疯;这是一个看似复杂的问题!流行的“只设置 CURLOPT_POST 不是答案,因为 PHP cURL 会自动为您完成。(php.net/manual/en/function.curl-setopt.php#108162)
  • 我已经能够使用您的代码创建一个新域。您可以使用 curl_getinfo($ch, CURLINFO_RESPONSE_CODE) 来获取 POST 操作的 HTTP 响应代码。它应该返回 201 以成功创建。
  • 尝试了您的代码,它可以正常工作。该错误不是curl错误而是数字海洋错误,并且可能错误消息具有欺骗性,您可能需要检查您的域名是否正确以及IP地址是否正确。如果失败,那么也许您想检查您的计算机和 curl 版本。在 PHP 7 上测试,curl 版本 = 7.0.16

标签: php json rest curl digital-ocean


【解决方案1】:

为 POST 请求添加 Content-Length 标头并使用 CURLOPT_POST 选项

function basic_api_handle($key, $method, $URI, $data) {
    $json = json_encode($data)
    $headers = array(
        'Authorization: Bearer '.$key,
        'Content-Type: application/json'
    );
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_URL, $URI);

    if ( $method === 'POST' ) {
        curl_setopt($curl, CURLOPT_POST, 1);
    } else {
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        array_push($headers, 'Content-Length: ' . strlen($json) );
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers)
    curl_setopt($ch, CURLOPT_POSTFIELDS, $json );
    $result = curl_exec($ch);
    if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
    curl_close($ch);
    return json_decode($result, true);
}

【讨论】:

  • 嗨!谢谢,但我已经尝试过了,它没有任何区别,URL编码或http_build_headers :(
  • 你也可以尝试使用CURLOPT_POST
【解决方案2】:

也许这对你有用:

function basic_api_handle($key, $method, $URI, $data) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); // <-- Should be set to "GET" or "POST"
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // <-- Maybe the SSL is the problem

    curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"); // <-- I am not familiar with this API, but maybe it needs a user agent?
    curl_setopt($ch, CURLOPT_VERBOSE, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Authorization: Bearer '.$key,
        'Content-Type: application/json')
    );

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($ch, CURLOPT_URL, $URI);
    curl_setopt($ch, CURLOPT_POST, count($data)); // <-- Add this line which counts the inputs you send
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

    $result = curl_exec($ch);
    if($result === false) error_log("API ERROR: Connection failure: $URI", 0);

    curl_close($ch);

    return json_decode($result, true);
}

这也可能是您应该发送的标题和丢失它的问题。

【讨论】:

  • CURLOPT_POST 不像你想象的那样工作。它要么是 1/0(真/假),要么是开/关。此外,他的帖子字段不是 http 编码的。
  • 关闭验证主机和验证对等非常不安全。 curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYPEER.html
  • 错误 - 当您需要获取网页的内容但您不关心它的身份验证时,这就是您必须做的。
  • 我确实需要关注身份验证 - 我会尝试计数的想法...
【解决方案3】:

可能是 307 或 308 http 重定向。

也许“https://api.digitalocean.com/v2/domains”会重定向到另一个网址。

如果是这种情况,请尝试添加:

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

让 curl 跟随重定向并保留参数。 建议您也使用:

curl_setopt($curl, CURLOPT_POSTREDIR, 3);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");

保留请求正文。 希望对您有所帮助。

【讨论】:

  • 感谢您的帮助,虽然我确实尝试过 :( 似乎不是问题。
【解决方案4】:

从技术上讲,这不是一个修复,而是一个解决方法。 感谢大家的 cmets 和想法,不幸的是,没有任何工作/修复代码并且赏金已过期 :(

虽然我不知道为什么 PHP cURL 选项不起作用(HTTP 起作用,只是 Digital Ocean 因与验证帖子数据相关的未知原因吐出错误)...

我确实有一个新方法可以工作终于...(感谢jtittle post on the Digital Ocean Community forum

以防万一该链接将来失效...他是使用流和 file_get_contents 的工作函数,不是 curl...

<?php
function doapi( $key, $method, $uri, array $data = [] )
{
    /**
     * DigitalOcean API URI
     */
    $api = 'https://api.digitalocean.com/v2';

    /**
     * Merge DigitalOcean API URI and Endpoint URI
     *
     * i.e if $uri is set to 'domains', then $api ends up as
     *     $api = 'https://api.digitalocean.com/v2/domains'
     */
    $uri = $api . DIRECTORY_SEPARATOR . $uri;

    /**
     * Define Authorization and Content-Type Header.
     */
    $headers = "Authorization: Bearer $key \r\n" .
               "Content-Type: application/json";

    /**
     * If $data array is not empty, assume we're passing data, so we'll encode
     * it and pass it to 'content'. If $data is empty, assume we're not passing
     * data, so we won't sent 'content'.
     */
    if ( ! empty( $data ) )
    {
        $data = [
                    'http'          => [
                        'method'    =>  strtoupper( $method ),
                        'header'    =>  $headers,
                        'content'   =>  json_encode( $data )
                    ]
                ];
    }
    else
    {
        $data = [
                    'http'          => [
                        'method'    =>  strtoupper( $method ),
                        'header'    =>  $headers
                    ]
                ];
    }

    /**
     * Create Stream Context
     * http://php.net/manual/en/function.stream-context-create.php
     */
    $context = stream_context_create( $data );

    /**
     * Send Request and Store to $response.
     */
    $response = file_get_contents( $uri, false, $context );

    /**
     * Return as decoded JSON (i.e. an array)
     */
    return json_decode( $response, true );
}

/**
 * Example Usage
 */

var_dump(doapi(
    'do-api-key',
    'get',
    'domains'
));

我用这个来实际成功发布数据...

var_dump(doapi(
    $api_key,
    'post',
    'domains',
    array("name" => (string) $newDomain, "ip_address" => "1.2.3.4")
));

【讨论】:

  • 请记住...如果您要添加引用其他域名的域记录(如 CNAME 或 MX),则需要在域名末尾添加一个点 .
【解决方案5】:

您也可以尝试使用 CURLOPT_POST

【讨论】:

    猜你喜欢
    • 2013-08-01
    • 2018-07-15
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 1970-01-01
    相关资源
    最近更新 更多