ホームページ  >  記事  >  バックエンド開発  >  PHP5.0~5.6各種バージョン対応 cURLファイルアップロード機能

PHP5.0~5.6各種バージョン対応 cURLファイルアップロード機能

不言
不言オリジナル
2018-06-01 11:51:221496ブラウズ

この記事では、主に PHP5.0 ~ 5.6 のさまざまなバージョンと cURL ファイルのアップロード機能の互換性について紹介し、PHP のさまざまな一般的なバージョンの CURL ファイルのアップロード操作に関連する実装スキルと注意事項を例の形式で分析します。必要な方は参考にしてください

この記事は、PHP5.0~5.6の各バージョンの互換性のcURLファイルアップロード機能を分析する例を使用しています。参考のために皆さんと共有してください。詳細は次のとおりです:

最近の要件は、PHP 経由で cURL を呼び出して、multipart/form-data 形式でファイルをアップロードすることです。いくつかの落とし穴があれば、記事としては十分です。

重要な警告

PHP の公式中国語ドキュメントは読まないでください。バージョンが追いつかないと死んでしまいます!

PHP の異なるバージョン間の cURL の違い

PHP の cURL は、(文字列の代わりに) 連想配列を CURL_POSTFIELDS に渡すことにより、multipart/form-data POST リクエスト。 <code>CURL_POSTFIELDS传递关联数组(而不是字符串)来生成multipart/form-data的POST请求。

传统上,PHP的cURL支持通过在数组数据中,使用“@+文件全路径”的语法附加文件,供cURL读取上传。这与命令行直接调用cURL程序的语法是一致的:

curl_setopt(ch, CURLOPT_POSTFIELDS, array(
  &#39;file&#39; => &#39;@&#39;.realpath(&#39;image.png&#39;),
));

equals

$ curl -F "file=@/absolute/path/to/image.png" <url>

但PHP从5.5开始引入了新的CURLFile类用来指向文件。CURLFile类也可以详细定义MIME类型、文件名等可能出现在multipart/form-data数据中的附加信息。PHP推荐使用CURLFile替代旧的@语法:

curl_setopt(ch, CURLOPT_POSTFIELDS, [
  &#39;file&#39; => new CURLFile(realpath(&#39;image.png&#39;)),
]);

PHP 5.5另外引入了CURL_SAFE_UPLOAD选项,可以强制PHP的cURL模块拒绝旧的@语法,仅接受CURLFile式的文件。5.5的默认值为false,5.6的默认值为true。

但是坑的一点在于:@语法在5.5就已经被打了deprecated,在5.6中就直接被删除了(会产生 ErorException: The usage of the @filename API for file uploading is deprecated. Please use the CURLFile class instead)。

对于PHP 5.6+而言,手动设置CURL_SAFE_UPLOAD为false是毫无意义的。根本不是字面意义理解的“设置成false,就能开启旧的unsafe的方式”——旧的方式已经作为废弃语法彻底不存在了。PHP 5.6+ == CURLFile only,不要有任何的幻想。

我的部署环境是5.4(仅@语法),但开发环境是5.6(仅CURLFile)。都没有压在5.5这个两者都支持过渡版本上,结果就是必须写出带有环境判断的两套代码。

现在问题来了……

环境判断:小心魔法数字!

我见过这种环境判断的代码:

if (version_compare(phpversion(), &#39;5.4.0&#39;) >= 0)

我对这种代码的评价只有一个字:屎。

这个判断掉入了典型的魔法数字陷阱。版本号莫名其妙的出现在代码之中,不查半天PHP手册和更新历史,很难明白作者被卡在了哪个功能的变更上。

代码应该回归本源。我们的实际需求其实是:有CURLFile就优先采用,没有再退化到传统@语法。那么代码就来了:

if (class_exists(&#39;\CURLFile&#39;)) {
  $field = array(&#39;fieldname&#39; => new \CURLFile(realpath($filepath)));
} else {
  $field = array(&#39;fieldname&#39; => &#39;@&#39; . realpath($filepath));
}

建议明确指定的退化选项

从可靠的角度,推荐指定CURL_SAFE_UPLOAD的值,明确告知php是容忍还是禁止旧的@语法。注意在低版本PHP中CURLOPT_SAFE_UPLOAD常量本身可能不存在,需要判断:

if (class_exists(&#39;\CURLFile&#39;)) {
  curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
} else {
  if (defined(&#39;CURLOPT_SAFE_UPLOAD&#39;)) {
    curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
  }
}

cURL选项设置的顺序

不管是curl_setopt()单发还是curl_setopt_array()批量,cURL的选项总是设置一个生效一个,而设置好的选项立刻就会影响cURL在设置后续选项时的行为。

例如CURLOPT_SAFE_UPLOAD就和CURLOPT_POSTFIELDS的行为有关。如果先设置CURLOPT_POSTFIELDS再设置CURLOPT_SAFE_UPLOAD,那么后者的约束作用就不会生效。因为设置前者时cURL就已经把数据实际的识读处理完毕了!

cURL有那么几个选项存在这种坑,务必小心。还好这种存在“依赖关系”的选项不多,机制也不复杂,简单处理即可。我的方法是先批量设置所有的选项,然后直到curl_exec()的前一刻才用curl_setopt()单发设置CURLOPT_POSTFIELDS

従来、PHP の cURL は、cURL が読み取りおよびアップロードする配列データで「@+完全なファイル パス」構文を使用することによるファイルの添付をサポートしていました。これは、コマンド ラインから cURL プログラムを直接呼び出すための構文と一致しています: 🎜

🎜rrreee🎜🎜🎜equals🎜

🎜rrreee🎜🎜🎜しかし、PHP は5.5 から導入 新しい CURLFile クラスは、ファイルを指すために使用されます。 CURLFile クラスは、multipart/form-data データに表示される MIME タイプ、ファイル名などの追加情報を詳細に定義することもできます。 PHP では、CURLFile を使用して古い @ 構文を置き換えることをお勧めします。 🎜

🎜rrreee🎜🎜🎜PHP 5.5 では、CURL_SAFE_UPLOAD オプションも導入されています。 PHP cURL モジュールは古い @ 構文を拒否し、CURLFile スタイルのファイルのみを受け入れます。デフォルト値は、5.5 の場合は false、5.6 の場合は true です。 🎜🎜しかし、落とし穴は次のとおりです。@ 構文は 5.5 で非推奨になり、5.6 で直接削除されました (ElorException が生成されます: @filename code> API の使用法ファイルのアップロードは非推奨です。代わりに CURLFile クラスを使用してください)。 🎜🎜PHP 5.6 以降の場合、<code>CURL_SAFE_UPLOAD を手動で false に設定しても意味がありません。これは、文字通り「false に設定すると安全でない古いメソッドが有効になる」とは理解されていません。古いメソッドは廃止された構文として完全に存在しなくなりました。 PHP 5.6+ == CURLFile のみ🎜、幻想を抱かないでください。 🎜🎜私のデプロイ環境は 5.4 (@Grammar のみ🎜) ですが、開発環境は 5.6 (CURLFile のみ🎜) です。どちらも、両方がサポートする移行バージョンである 5.5 には焦点を当てていないため、環境判断を備えた 2 セットのコードを作成する必要があります。 🎜🎜さて問題は… 🎜🎜🎜🎜環境判断: 魔法の数字に注意してください! 🎜🎜🎜🎜私はこの種の環境判定コードを見たことがあります: 🎜

🎜rrreee🎜🎜🎜 この種のコードについては、「クソ」の一言しかありません。 🎜🎜この判断は、典型的なマジックナンバーの罠に陥ります。コード内にバージョン番号が不可解に表示されるため、PHP マニュアルや更新履歴を長時間確認しないと、作成者がどの機能変更に引っかかっているのかを理解するのは困難です。 🎜🎜コードはそのルーツに戻る必要があります。実際のニーズは、従来の @ 構文に戻らずに、最初に CURLFile を使用することです。コードは次のとおりです: 🎜

🎜rrreee🎜🎜🎜🎜🎜劣化オプションを明示的に指定することをお勧めします🎜🎜🎜🎜信頼性の観点から、CURL_SAFE_UPLOAD、古い <code>@ 構文を許容するか禁止するかを PHP に明示的に指示します。 CURLOPT_SAFE_UPLOAD 定数自体は、PHP の以前のバージョンには存在しない可能性があることに注意してください。 🎜

🎜rrreee🎜🎜🎜🎜🎜cURL オプションの設定順序🎜🎜🎜 🎜 curl_setopt() シングルショットまたは curl_setopt_array() バッチに関係なく、cURL のオプションは常に 1 つずつ有効になり、設定されたオプションは後続のオプションを設定するときにすぐに cURL に影響します。の動作。 🎜🎜たとえば、CURLOPT_SAFE_UPLOADCURLOPT_POSTFIELDS の動作に関連しています。 CURLOPT_POSTFIELDS が最初に設定され、次に CURLOPT_SAFE_UPLOAD が設定された場合、後者の制約は有効になりません。なぜなら、前者を設定すると、cURL はデータの実際の読み取りと処理をすでに完了しているからです。 🎜🎜cURL には、この落とし穴があるオプションがいくつかあるため、注意してください。幸いなことに、この種の「依存関係」には選択肢は多くなく、仕組みも複雑ではないため、簡単に扱うことができます。私の方法は、最初にすべてのオプションをバッチで設定し、次に curl_setopt() を使用して、curl_exec()の直前まで一度に CURLOPT_POSTFIELDS を設定します。 >。 🎜

実際、curl_setopt_array() で使用される配列では、後ろの CURLOPT_POSTFIELDS の位置も信頼できることが保証されています。 PHP の連想配列はシーケンシャルに保証されており、 curl_setopt_array() の内部実行順序は最初から最後まで順番である必要があると仮定することもできます (そう仮定するのが良いことではないことはわかっていますが、一部の場合は)。あまりにも単純すぎるので、事実について最低限の主張をさせてください)ので、安心してください。 curl_setopt_array()用的数组中,保证CURLOPT_POSTFIELDS的位置在后边也是可靠的。PHP的关联数组是有顺序保障的,我们也可以假设curl_setopt_array()内部的执行顺序一定是从头到尾按顺序(好吧我知道assume不是件好事,不过有些实在过分浅显的事实,就容我下个最低限度的断言吧),所以尽可放心。

我的做法只是在代码表现上加个多余的保险,突出强调顺序的重要性防以后手贱。

命名空间

PHP 5.2或以下的版本没有命名空间。代码中用到了空间分隔符就会引发解析器错误。要照顾PHP 5.2其实容易想,放弃命名空间即可。

要注意的反倒是有命名空间的PHP 5.3+。无论是调用CURLFile还是用class_exists()判断CURLFile的存在性,都推荐写成CURLFile

私のアプローチは、コードのパフォーマンスにさらなる保険を追加し、将来の間違いを防ぐための順序の重要性を強調することです。


名前空間

PHP バージョン 5.2 以前には名前空間がありません。コード内でスペース区切り文字 を使用すると、パーサー エラーが発生します。 PHP 5.2 を扱うのは実際には簡単で、名前空間を放棄するだけです。

注意する必要があるのは、名前空間を備えた PHP 5.3 以降です。 CURLFile を呼び出す場合でも、class_exists() を使用して CURLFile の存在を確認する場合でも、CURLFile を記述してトップレベルのスペースを明確に指定し、次のような場合にコードがクラッシュしないようにすることをお勧めします。名前空間にラップされます。

関連おすすめ:

php5、php7のcURLファイルアップロード機能に対応🎜🎜🎜🎜🎜🎜🎜🎜

以上がPHP5.0~5.6各種バージョン対応 cURLファイルアップロード機能の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。