質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.36%
URL

URL(ユニフォームリソースロケータ)とは、インターネット上のリソース(Webページや電子メールの宛先等)を特定するための形式的な記号の並びの事を言う。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

457閲覧

PHPによるURLの判定の不具合

Lapius

総合スコア1

URL

URL(ユニフォームリソースロケータ)とは、インターネット上のリソース(Webページや電子メールの宛先等)を特定するための形式的な記号の並びの事を言う。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2024/08/23 23:34

編集2024/08/24 03:37

実現したいこと

  • 日本語だと通過できるようなコードにしたい。

詳細

$urlに日本語が含まれたURL(例: https://example.com/あいうえお )の場合に「URLの形式が正しくありません。正しいURLを入力してください。」になる理由が分かりません。
そこまで詳しいわけではないので分かりやすく説明・修正方法をご提示ください。
宜しくお願い致します。

該当のソースコード(一部)

php

1 if ($url !== null) { 2 if (!isValidURL($url)) { 3 $errors[] = "URLの形式が正しくありません。正しいURLを入力してください。"; 4 } 5 } 6 7~~~ 8 9function isValidURL($url) { 10 return filter_var($url, FILTER_VALIDATE_URL) && preg_match("/^(https?):/", $url); 11}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

URLに使える文字は決まっていて、それ以外の文字はエンコードします。
URLはいくつかのパートに別れているので、パート毎に使える文字の範囲が異なります。

PHPでどうするのが普通なのかよく知りませんが、例えば、

PHP

1$url="https://api.kmr1.org/v1/?" . http_build_query(["url"=>"https://example.com/あいうえお"]);

で、クエリーパラメーターの中のurlの値がエンコードされます。

投稿2024/08/24 02:10

otn

総合スコア85842

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

PHP 8.3.8で確認しました。

isValidURL関数に1行追加します。

function isValidURL($url) { $url = idn_to_ascii($url); return filter_var($url, FILTER_VALIDATE_URL) && preg_match("/^(https?):/", $url); }

https://www.php.net/manual/ja/filter.filters.validate.php
のFILTER_VALIDATE_URLには、「この関数は、ASCII の URL のみを正しいとみなすことに注意しましょう。 国際化ドメイン名 (非 ASCII 文字を含むもの) は失敗します。」とあります。

idn_to_ascii
https://www.php.net/manual/ja/function.idn-to-ascii.php

(訂正)
最初の回答は、国際化ドメインと日本語URLを勘違いしていました。申し訳ございませんでした。

isValidURL関数に3行追加します。

function isValidURL($url) { $url = rawurlencode($url); $url = str_replace("%3A", ":", $url); $url = str_replace("%2F", "/", $url); return filter_var($url, FILTER_VALIDATE_URL) && preg_match("/^(https?):/", $url); }

(訂正・その2)
otnさんの指摘により訂正します。

isValidURL関数に5行追加します。

function isValidURL($url) { $url = rawurlencode($url); $url = str_replace("%3A", ":", $url); $url = str_replace("%2F", "/", $url); $url = str_replace("%3F", "?", $url); $url = str_replace("%3D", "=", $url); return filter_var($url, FILTER_VALIDATE_URL) && preg_match("/^(https?):/", $url); }

投稿2024/08/24 02:49

編集2024/08/24 13:44
hiroki-o

総合スコア1072

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lapius

2024/08/24 03:57

ご返信ありがとうございます。 無事日本語などが使えるようになったようですが、URLが60文字以上の場合にエラーになってしまうバグが発生しています、コード内では文字数を制限するロジックはありませんし、Mysqlの元URL部分のカラムもvarchar(2000)としているので問題ないはずです。 https://api.kmr1.org/v1/?url={ここにURLを入れるのですが試した感じ60字以上ならエラーになってしまいます}
Lapius

2024/08/24 04:01

URLによっては60文字じゃなくて90文字だったりもしました、より一層分からなくなりました...
hiroki-o

2024/08/24 04:16

エラーの内容を具体的に提示してください。idn_to_ascii、filter_var、preg_match、どこでエラーになりますか?
Lapius

2024/08/24 04:23

エラーというのは以下のようになるということです。語彙力なくてすみません { "errors": [ "URLの形式が正しくありません。正しいURLを入力してください。" ] }
Lapius

2024/08/24 04:24

文字数に関数処理が無いのにURLの文字数によって(特定文字数以上)処理が変わる意味が分かりません。
tezcello

2024/08/24 05:53

idn_to_ascii()は、デフォルトでは使えないのでは? __手元のPHP公式8.3Dockerイメージにはライブラリ等が含まれていないので使えない それに趣旨としては「国際化ドメイン」を使える様にするのであって、パス以下を変換するのに使うモノではない様に思いますけど? 標準的なモノで対策するなら、parse_url()で分解して、path'部を rawurlencode() を通すとかでしょう。 ただし、path部が多階層になっていると面倒です。
hiroki-o

2024/08/24 05:56

tezcelloさん おっしゃる通りです。国際化ドメインと日本語URLは異なりますね。 今、訂正した回答を考えていたところです。 Lapiusさん、tezcelloさん、申し訳ございませんでした。
Lapius

2024/08/24 07:16

確認した感じ完全に治りました! 本当にありがとうございました
otn

2024/08/24 11:38

上記の3行を追加すると、チェックするURLは、 "https://api.kmr1.org/v1/%3Furl%3Dhttps://example.com/%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A" という、実際にこのURLにアクセスしても目的ものが返ってこない、使えないURLなわけですが、 (PATH部分が "/v1/?url=https:/example.com/あいうえお" で、QUERY_STRINGが空。 加工前の本来のURLだと、PATHが"/v1/"で、QUERYが "url=https:/example.com/あいうえお") その実際に使えないURLをチェックしてどういう意味があるのか? まあ、質問者が「何のためにチェックしたいのか」という目的次第ですが。
hiroki-o

2024/08/24 13:49 編集

otnさん 私の回答で気分を害されたようで、申し訳ございませんでした。 最低限、filter_varとpreg_matchが通ればよいと思って、そのように回答しましたが、間違いだったのですね。 (となると、filter_varは、URLのチェックのあてにならない関数なのでしょうか?) ただ、私の回答が間違いだったとしても、これを読んだ人には $url = str_replace("%3F", "?", $url); $url = str_replace("%3D", "=", $url); を追加するくらいの機転は利かせてほしいなあと思います。 少しでも動くソースを提供したいと思って回答しましたが、100%完璧な回答しか許されないのでしょうか。 これの続きの質問が出ているようですが、今回は自粛します。
tezcello

2024/08/24 14:30

> 100%完璧な回答しか許されないのでしょうか そうではなく、「抜けている部分があるよ」という指摘のつもりだったのでしょう。 個人的には、URL全体を一気にrawurlencode()を通してしまったのが悪手だったかなと思います。 先にもコメントした様に、parse_url()で分解して、必要な部分を変換してから連結すべきだったんじゃないかと。 > 機転は利かせてほしいなあと思います。 激しく同意しますが、現実的には「動作するコード」が欲しいだけで、なぜ動作しない(期待した動作でない)のかの解説が欲しい訳じゃない場合が非常に多いと思います。 > 続きの質問が出ているようですが、今回は自粛します。 自粛は不要では? otnさんの指摘は回答へ向けたモノでは無く、質問に向けられたモノのはずですから。
guest

0

urlには日本語文字列は利用出来ません。
rawurlencode関数を通してurlエンコードする必要があります。

投稿2024/08/24 02:09

Eggpan

総合スコア3203

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問