URLから特定のパラメーターを除外した形を返す関数（JavaScript/PHP）

# 前置き

~~えらく雑に作られています。~~
~~案外考慮する点が多くて「とりあえずこれでいいか・・・・」と妥協した結果がこれだよ！！！~~
~~いい案（ロジック）があればご教授願いたい・・・・~~
~~※ 落ち着いたらブラッシュアップしていきます~~

コメントを頂けたおかげで、いくらかマシになりました！
（※『マシ』=> 提供いただいたスクリプトを改変してしまってるので・・・ ）

投稿時に記載していなくて申し訳ないですが、下記ブラウザを対象としています。

- IE10以上
- FireFox
- Chrome
- Safari
- (Edge) ※ 後々といったところです

# 本題

```
http://hoge.com/index.html?huga=true&hello=world&tanaka=tarou
```

みたいなURLがあったとします。


『hugaとhelloは非表示にしたいな～ :thinking: 』

ってときに↓こんな感じにトリミングしてくれる関数になります。（需要有るかな～～～）

```
http://hoge.com/index.html?tanaka=tarou
```

## JavaScript版

### 使い方

```javascript:script.js
var excludes = ['huga', 'hello']; // 除外したいパラメーターリスト
var url = "http://hoge.com/index.html?huga=true&hello=world&tanaka=tarou"; // トリム前のURL

console.log(trimToURL(excludes, url)); // レッツとりみんぐ！
```

### 関数

@mpywさんの[コメント](http://qiita.com/CyberMergina/items/4b5844a6bd5bcef80c5c#comment-45d1ed414d4342843657)を参考にさせていただきました！
改変を加えたところだけ注釈を入れます。
※ URLインターフェース非対応ブラウザの処理は @yama-tさんが提供してくださったロジックに置き換えたほうが簡素ですね><

```javascript:main.js

function trimToURL(excludes, url){
  var builder = { search: '', hash: '' }, baseUrl = url; /* builderオブジェクトを用意 */

  if ( !url ) return url;

  if ( typeof(URL) === "function" ) {
    var builder = new URL(url);
    baseUrl = builder.origin + builder.port + builder.pathname;
  }
  /* URLインスタンス非対応ブラウザ用 */  
  else {
    var tmpURL = url.split('?'), search = '', num = '', hash = '';
    // パラメーターを含んでいる場合
    if ( tmpURL[1] !== undefined ) {
      baseUrl = tmpURL[0]; // ? 以降を変数に格納
      search = tmpURL[1]; // ? 以降を変数に格納
      /* ハッシュの為の処理 */
      num = url.indexOf('#'); // # の位置を確認
      hash = (num > -1) ? url.substr(num) : ""; // # があった場合は、それ以降の文字列を変数に格納【更新(1)】
      search = '?' + search.replace(hash, ""); // # 以降の文字列をもとのURLから取り除き、変数に格納
      builder = { // エセURLインターフェースの戻り値作成
        search: search,
        hash: hash,
      };
    }
  }

  if (builder.search) {
    builder.search = "?" + builder.search.substr(1).split('&').filter(function (item) {
        return !excludes.hasOwnProperty(item.split('=', 2)[0]);
    }).join('&');
    builder.search = ( builder.search.search(/\?$/) < 0 ) ? builder.search : ""; // IE対策【更新(2)】
    // ↓現在はレガシーブラウザにも対応させる必要があったので悲しい書き方となっております
    return baseUrl + builder.search + builder.hash;
  }
  else {
    return url;
  }
}

```

**更新(1)**： `if ( -1 )` の結果はIEだとtrue, FireFoxとChromeとSafariだと falseのため、きちんと数値比較するようにしました。

```js:before
      hash = (num) ? '#' + url.substr(num) : ""; // # があった場合は、それ以降の文字列を変数に格納
```

**更新(2)**： filterの結果が空だった場合、`?` がFireFoxとChromeとSafariだと付与されなかったのですが、IEだと付与されるため、チェックを追加しました。

## PHP版

### 使い方

```php:index.php
$excludes = ['huga', 'hello']; // 除外したいパラメーターリスト
$url = "http://hoge.com/index.html?huga=true&hello=world&tanaka=tarou"; // トリム前のURL

echo trimToURL($excludes, $url); // レッツとりみんぐ！
```

### 関数

@mpywさんの[コメント](http://qiita.com/CyberMergina/items/4b5844a6bd5bcef80c5c#comment-9b606f3cbf8e4bfc77ed)を参考にさせていただきました！
改変を加えたところだけ注釈を入れます。

```php:index.php
function trimToURL($excludes, $url){
  $elements = parse_url($url);
  if (!isset($elements['query'])) return $url; // パラメーターがなかった場合は即時処理しない

  parse_str($elements['query'], $params);

  // パラメータが 「?hoge=huga」の形と 「?hoge」 の形に対応できるようにしたかったので処理を変えています
  $elements['query'] = "";
  // 現在ここがストレスです...
  foreach (array_diff_key($params, array_flip($excludes)) as $key => $val) {
    $elements['query'] .= ($elements['query'] !== "") ? "&" :  "";
    $elements['query'] .= (isset($val) && $val !== "") ? $key . "=" . $val : $key;
  }
  return build_url($elements);
}

function build_url(array $elements) {
    $e = $elements;
    return
        (isset($e['host']) ? (
            (isset($e['scheme']) ? "$e[scheme]://" : '//') .
            (isset($e['user']) ? $e['user'] . (isset($e['pass']) ? ":$e[pass]" : '') . '@' : '') .
            $e['host'] .
            (isset($e['port']) ? ":$e[port]" : '')
        ) : '') .
        (isset($e['path']) ? $e['path'] : '/') .
        (isset($e['query']) ? ( 
          is_array($e['query']) ?
            '?' . http_build_query($e['query'], '', '&') :
            (($e['query'] !== "") ? '?' . $e['query'] : '') /* パラメーターが無かった場合は「？」を付与しない */
        ) : '') .
        (isset($e['fragment']) ? "#$e[fragment]" : '');
}
```

## ひとりごと
結構単純な配列加工にループ文って使いたくないですね（使わずにかけるとカコイイ！！）
javascriptでいうmapやfilterを駆使したり、PHPでいうarray_mapやarray_walk(これは最近聞いた)とか
慣れていきたいところです・・・。