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

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

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

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

PHP

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

852閲覧

URLのパスに # や () がある場合に、parse_url() や new URL() はどのように使えばいいですか?

nikuatsu

総合スコア177

URL

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

PHP

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2022/04/20 10:25

編集2022/04/20 11:56

実現したいこと

パスに # や () があるURLを、JavaScriptとPHPでパースしたい(parse_url の結果や new URL() の結果と同じものを得たい)です。

発生している問題

例えば # がある場合、parse_url()path や、new URL()pathname が、# の手前で終わってしまいます。

該当のソースコード

こちらです。いずれも「#」の手前で終わってしまいます。

php

1$url = 'http://example.com/episode/ルパン三世(#3)'; 2$parse = parse_url($url); // path が "/episode/ルパン三世(" になってしまう 3var_dump( $parse );

JavaScript

1var url = 'http://example.com/episode/ルパン三世(#3)'; 2var parse = new URL(url); // pathname が "/episode/%E3%83%AB%E3%83%91%E3%83%B3%E4%B8%89%E4%B8%96(" になってしまう 3console.log( parse );

試したこと

phpでは urlencode()rawurlencode() をかけてみましたがこれではすべてが path として該当していまいました。

またJavaScriptでも同じようにencodeURI()encodeURIComponent()などをかけてみたのですが同じでした。

php

1$url = 'http://example.com/episode/ルパン三世(#3)'; 2$encode = urlencode($url); 3$parse = parse_url($encode); 4var_dump( $parse ); // path が全て該当してしまう 5 6$url = 'http://example.com/episode/ルパン三世(#3)'; 7$encode = rawurlencode($url); 8$parse = parse_url($encode); 9var_dump( $parse ); // path が全て該当してしまう

そしてMDNで見てますと

エスケープされないもの:
A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #

とありました。

もしかして、これらの文字列を一つずつ正規表現でパーセントエンコードする必要があるということでしょうか?例えばJavaScriptだとこうでしょうか?

JavaScript

1var url = 'http://example.com/episode/ルパン三世(#3)'; 2var encode = my_encodeURI(url); 3var parse = new URL(encode); 4console.log( parse ) 5console.log( my_decodeURI(parse.pathname) ); // 無事に pathname に "/episode/ルパン三世(#3)" が取得できる 6 7function my_encodeURI( url ){ 8 let result = encodeURI(url); 9 result = result.replace(/\#/g, '%23'); 10 result = result.replace(/\(/g, '%28'); 11 result = result.replace(/\)/g, '%29'); 12 return result; 13} 14 15function my_decodeURI( url ){ 16 let result = decodeURI(url); 17 result = result.replace(/%23/g, '#'); 18 result = result.replace(/\%28/g, '()'); 19 result = result.replace(/%29/g, ')'); 20 return result; 21}

こんな手作業でやらずともビシっとよしなにしてくれる方法がありそうに思えたので質問させて頂きました。
宜しくお願い致します。

実際の使い方

尚、実際の使い方としては、このようなaタグをクリックした際にJavaScrpitでPOSTし、phpでパスを分解する、などを想定しております。
<a href="http://example.com/episode/ルパン三世(#3)">ルパン三世(#3)</a>

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

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

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

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

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

arcxor

2022/04/20 11:54

> $url = 'http://example.com/episode/ルパン三世(#3)'; こんな URL を前提にしたらうまくいくはずがないでしょう。 # はフラグメントの区切り文字です。# 以降はフラグメントとして扱われます。それはパスの一部ではありません。 どういう状況でURLを処理したいのか、前提をもう少し詳しく書いてください。
nikuatsu

2022/04/20 11:59

ありがとうございます。なんと、URL自体がそもそもアウトでしたか。 ちょうど「実際の使い方」としてイメージを追加したのですが、こんなhrefは使わぬ方がいいでしょうか?
nikuatsu

2022/04/20 12:50

ということは、<a>クリック時に、質問にある const url = my_encodeURI(href); をかけて、このurlをPOSTするという手続きがベストでしょうか? それとも#を使うこと自体避けた方がいいですか?
guest

回答2

0

ベストアンサー

そもそもの考え方がおかしいのでは?

PHP

1<?PHP 2$url = 'http://example.com/episode/'.urlencode('ルパン三世(#3)'); 3$parse = parse_url($url); 4var_dump( $parse ); 5print urldecode($parse["path"]);

追記

パラメータで「ルパン三世(#3)」を渡す

PHP

1<?PHP 2print_r($_GET); 3?> 4<a href="?q=%E3%83%AB%E3%83%91%E3%83%B3%E4%B8%89%E4%B8%96(%233)">ルパン三世(#3)</a>

上記クリックすると「Array ( [q] => ルパン三世(#3) )」が確認できます

むりやりpostする

javascript

1<?PHP 2print_r($_POST); 3?> 4<script> 5document.addEventListener('click',e=>{ 6 if(e.target.matches('a')){ 7 e.preventDefault(); 8 const h=e.target.getAttribute('href').split(/\/(?=[^\/]+$)/); 9 const f=`<form method="post" action="${h[0]}" id="f" style="position:absolute;top:-999"> 10 <input name="q" value="${h[1]}"> 11 <input type="submit" value="send"> 12 </form>`; 13 document.body.insertAdjacentHTML('beforeend',f); 14 document.querySelector('#f').submit(); 15 } 16}); 17</script> 18 19<a href="http://example.com/episode/ルパン三世(#3)">ルパン三世(#3)</a>

投稿2022/04/20 10:30

編集2022/04/21 01:04
yambejp

総合スコア114843

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

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

nikuatsu

2022/04/20 11:18

すみません、$urlはPOSTされる値なので、1つにまとまった状態を考えていました。 それでもパス部分とホスト部分などに分けてPOSTしてから、ご回答のように繋げるべきでしょうか?
nikuatsu

2022/04/20 11:53

ああしかし、JavaScript側でパス部分に分けようと思っても、その時点で # の手前までしかパスとして取得できないのです。 改めて問い直すなら、例えばこちらをクリックしたときに、どのようにPOSTし、PHPでパスに分解すべきでしょうか? <a href="http://example.com/episode/ルパン三世(#3)">ルパン三世(#3)</a>
yambejp

2022/04/21 00:21

いろいろな部分で知識が足りていないのだと思います まず、普通のHTMLではリンクをクリックしてもpostされることはありません あえていえばgetです。urlに日本語や特殊な希望はいれられません。 またPHPでパスに分解するというのも認識がずれているとおもいます 参考データを追記しておきます
nikuatsu

2022/04/21 00:52 編集

参考データありがとうございます。そういえばパラメータにしたり、あらかじめhrefをパーセントエンコードしておくのはいいですね。 あらかじめでなくクリックした際にエンコードとPOSTするならば、以下の感じではいかがでしょうか? まずパス内の#のみをパーセントエンコードします。 function cnv_hash_to_percent( url ){ let arr = url.split('/'); const last = arr[arr.length-1]; arr.splice(-1,1); // arr = arr.map((v)=>{ return v.replace(/\#/g, '%23'); }); const result = arr.join('/') + '/' + last; return result; } これを使って、以下のようにPOSTする流れです。 <a href="http://example.com/episode/ルパン三世(#3)">ルパン三世(#3)</a> $('a').click(function(e){ e.stopPropagation(); e.preventDefault(); const url = cnv_hash_to_percent( $(this).attr('href') ); $.ajax({ url: "http://example.com/ajax", type: "POST", data: {url} }).done(function( res ) { // ルパン三世(#3)にまつわるjsonがresに入っている }); }); でPHP側で parse_url($url); をしてパスに分けて、cnv_hash_to_percentの逆をやって#に戻し、ルパン三世(#3) の文字列を得て、この文字列でSQLを流して、結果をjsonにして上記JavaScrpitのresに返す流れです。
yambejp

2022/04/21 00:48

リンクとしては"ルパン三世(#3)"までを含むパスにアクセスしているのですから httpd側のRewriteRuleが必要になってきますね それにしても日本語を直書きするのは相当な悪手です。 aタグでパスの最後の文字列を日本語にしてどうしてもpostしたいというなら やりようはありますが、hrefのハッシュが使えなくなるのでページ内移動ができなくなりますが 本当によいのでしょうか?
nikuatsu

2022/04/21 00:56

hrefに日本語直書きは悪手なのですね。あなたがそう仰るなら即座にやめますw 色々な懸念のご提示ありがとうございます。
yambejp

2022/04/21 01:05

無理やりバージョン書いておきましたので参考にしてください
nikuatsu

2022/04/21 01:13

ありがとうございます。postする値は必要最低限の方がいいですね。それにsplitの正規表現も参考になりました。
guest

0

フラグメント識別子

javascript

1var url = 'http://example.com/episode/ルパン三世(#3)';

"#" はフラグメント識別子で予約されています。
pathname上に "#" を使うためにはパーセントエンコードしなければなりません。

javascript

1console.log(new URL('http://example.com/episode/ルパン三世(%233)').pathname); // "/episode/%E3%83%AB%E3%83%91%E3%83%B3%E4%B8%89%E4%B8%96(%233)"

パーセントエンコード

またJavaScriptでも同じようにencodeURI() や encodeURIComponent()などをかけてみたのですが同じでした。

"#" をエンコードすると、URLハッシュが消失して意味が変化してしまう為、"#" をエンコードしない仕様なのでしょう。
"#" がフラグメント識別子なのか、pathnameなのか、をURL文字列から機械的に判定するのは不可能です。

期待通りにエンコードするには、pathnameとURLハッシュを別々に受け取る等、区別できるためのロジックが必要です。

Re: nikuatsu さん

投稿2022/04/20 12:29

編集2022/04/20 12:30
think49

総合スコア18164

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

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

nikuatsu

2022/04/21 00:43 編集

ありがとうございます。たしかに、#をパーセントエンコードするなら質問のmy_encodeURIではダメで、パスだけに限定しなければいけませんね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問