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

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

ただいまの
回答率

87.37%

【PHP】レンタルサーバーにファイルをあげると、ローカルと挙動が変化する問題。

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,086
退会済みユーザー

退会済みユーザー

初めまして。

レンタルサーバーのロリポップにファイルをアップロードしたところ、ローカルとは異なる動きをしたため、その原因と対処法をお聞きしたく質問しました。

言語はPHPです。

PHP5.4、windows10です。

実行結果が異なっているので、その画像を用意しました。

ローカルでの実行結果(正しい結果)
イメージ説明

レンタルサーバでの実行結果
イメージ説明

PHPのソースです。

<?php
header('Content-Type: text/html; charset=UTF-8');
require_once 'lib/dump.php';

// 値の受け取り
foreach ($_POST as $key => $value) {
  if(!empty($value) && $key != 'mode'){
    $post[] = $value;
  }

  // 移動手段取得
  if($key == 'mode'){
    $mode = $value;
  }
}

/* リクエスト用の目的地準備 */
// $postの要素数を取得
$index_sum = count($post);
// 目的地連結用変数
$destination = '';

// 目的地連結
foreach ($post as $key => $value) {
  // 配列の0番目は出発地なので除外
  if($key != 0){
    // 目的地の追加
    $destination .= $post[$key];
    // 最後の要素以外なら連結記号を追加
    if($key+1 != $index_sum){
      $destination .= '|';
    }
  }
}

// apiのリクエストURL
$url = "https://maps.googleapis.com/maps/api/distancematrix/json?origins=".$post[0].'|'.$destination."&destinations=".$destination."&mode='".$mode."'&language=ja&key=AIzaSyDkfDsdgdhfjgkhNl4wMj8rV3WTlg";
// jsonデータを文字列として読み込む
$json = file_get_contents($url);
// 文字化け対策
$json = mb_convert_encoding($json, 'UTF8', 'ASCII,JIS,UTF-8,EUC-JP,SJIS-WIN');
// jsonデータを連想配列に変換
$arr = json_decode($json,true);
// vardump($arr);

if ($arr === NULL) {
  /* 値がない場合(失敗) */
  print '失敗';
}else{
  /* 値がある場合(成功) */ 

  // 最適ルート取得用配列
  $result_route = array();
  // 時間比較箇所指定変数
  $seach_point = 0;
  // 既出箇所指定配列
  $drop_point = array();
  // 既出箇所指定配列の要素数取得用
  $drop_cnt = 0;
  // 出発地+目的地分のループ
  for($i=0; $i<$index_sum-1; $i++){
    // 最適ルートの取得
    $result_route[$i] = best_route($arr,$seach_point,$drop_point,$drop_cnt);
    // 探索用添え字取得
    $seach_point = $result_route[$i][0];
    // 既出箇所添え字取得
    $drop_point[] = $result_route[$i][0]-1;
    // 既出箇所指定配列の要素数取得
    $drop_cnt = count($drop_point);
  }

  // 表示用配列へ格納
  foreach ($post as $key => $value) {
    if($key != 0){
      // 目的地
      $result_destination[] = $post[$result_route[$key-1][0]];
      // 移動時間
      $result_time[] = $result_route[$key-1][2];
    }
  }
}

/**********
* 最適ルート構築メソッド
* $arr : APIレスポンス
* $row_i : 探索場所添え字
* $drop_point : 探索対象外指定添え字入り配列
* $drop_cnt : 探索対象外指定添え字数
**********/
function best_route($arr,$row_i,$drop_point,$drop_cnt){
  // 単体策対象外の指定上限判定用カウンター兼添え字用変数
  $drop_if_cnt = 0;
  // 目的地までの各時間取得を取得
  foreach ($arr['rows'][$row_i]['elements'] as $key => $value) {
    if(!empty($drop_point)){
      // 添え字が要素数を超えない為の対策
      if($drop_cnt > $drop_if_cnt){
        // 既に最適目的地とされた場所は排除する
        if($drop_point[$drop_if_cnt] != $key){
          // 時間を分単位に変換し、数値だけにする
          $duration[] = time_change($arr['rows'][$row_i]['elements'][$key]['duration']['text']);
          // 添え字インクリメント
          $drop_if_cnt++;
          // 表示用に時間取得
          $output_time[] = $arr['rows'][$row_i]['elements'][$key]['duration']['text'];
        }else{
          // 添え字合わせに要素の追加
          $duration[] = 999;
          $output_time[] = null;
        }
      }else{
        // 比較対象がなくなれば無条件で取得
        $duration[] = time_change($arr['rows'][$row_i]['elements'][$key]['duration']['text']);
        // 表示用に時間取得
        $output_time[] = $arr['rows'][$row_i]['elements'][$key]['duration']['text'];
      }
    }else{
      // 初回は無条件で取得
      $duration[] = time_change($arr['rows'][$row_i]['elements'][$key]['duration']['text']);
      // 表示用に時間取得
      $output_time[] = $arr['rows'][$row_i]['elements'][$key]['duration']['text'];
    }    
  }
  // 数字的に昇順でソート
  asort($duration,SORT_NUMERIC);
  // vardump($duration);

  $temp_first_p = array_keys($duration);
  $first_p = array_shift($temp_first_p);
  // 返却用配列に最適目的地添え字を格納
  $return_arr[0] = $first_p + 1;
  // 返却用配列に最適目的地までの時間を格納
  $return_arr[1] = array_shift($duration);
  // 返却用配列に表示用時刻を格納
  $return_arr[2] = $output_time[$first_p];

  return $return_arr;
}

/**********
* 文字列で取得された時間を数値に変換するメソッド
* 分単位
* 「m分」「H時間m分」
**********/
function time_change($time_str){
  /* 「m分」 */
  if(mb_strlen($time_str) < 4){
    // 文字列を配列化
    $arr1 = str_split($time_str); 
    $time = '';
    foreach ($arr1 as $key => $value) {
      if(ctype_digit($value)){
        // 数値のみ配列に格納
        $time .= $value; 
      }
    }
  }else{
    /* 「H時間m分」 */
    // 文字列を配列化
    $arr = str_split($time_str); 
    $flg = 0;
    $time = 0;
    foreach ($arr as $key => $value) {
      if(ctype_digit($value)){
        // 数値のみ配列に格納
        $time += (int)$value; 
      }else if($flg == 0){
        // 時間に60を掛けて分単位に変換
        $time_h = $time * 60; 
        $time = 0;
        $flg = 1;
      }
    }
    $time = $time_h + $time;
  }
  return $time;
}
?>

実行結果に違いがある理由と対処法が知りたいです。
よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • shi_ue

    2017/06/29 13:13

    google map の apiキーはダミーですよね?もし本物なら差し替えたほうがよろしいかと。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2017/06/29 20:44

    指摘ありがとうございます。そのままでしたので差し替えました。

    キャンセル

回答 4

+3

どちらの結果が意図した結果なのでしょうか?
正しいものを基準に切り分けていく必要があります。

中身の確認はしていませんが、検索結果が変わっているということは、API へ投げる内容に問題があると思います。
エンコードの失敗や文字化け等で、パラメータが効いていないとかじゃないでしょうか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/29 07:30

    回答ありがとうございます。
    ローカルでの実行結果が意図した動きです。
    質問を編集しました。

    APIへ投げる内容と返却された内容を確認しましたが、一致していました。

    キャンセル

  • 2017/06/29 12:07

    file_get_contents だと、request と response の確認が結構大変な気がしますが、確認した内容は 「vardump($arr) が一致した」とかですかね?

    $arr が正しく、その表示結果が変わるのであれば、その加工途中で各変数に差異が出る箇所があるはずなので、それを切り分けてみるのが適切です。
    あまり人のコードを読むのが得意ではないので、「どこが」までの特定は出来ませんが、何箇所かで途中経過を出力させれば、切り分けはできると思います。

    ただ、普通に考えると、同じスクリプトを通して挙動が変わるのは珍しいので、どっかでエラーが出ていないですかね?
    本番環境のエラー抑止を解除して、確認してみてはいかがでしょうか?

    キャンセル

  • 2017/06/29 21:36

    回答ありがとうございます。
    time_change関数がうまく機能しておらず、想定外の動きをしていました。

    キャンセル

+1

直接的な回答になりませんが。

まずは。PHPのバージョンや、環境情報を確認されてはいかがでしょうか。

あとは、レンタルサーバなので、ログが確認できなければ画面に、途中結果を出力するようにして
どこで違いがでるかを確認すると解決の糸口が見えるのではないでしょうか。

$JSONが同じとこまでは確認されてるようなので、なんらかの関数(array_keysとか)は
順序が保障されていないとかで、意図しない動きになっているとか・・・(想像)

地味ですが、最終結果が違うなら、途中のどこかの想定外の動き探すしかないかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/29 21:36

    回答ありがとうございます。
    time_change関数がうまく機能しておらず、想定外の動きをしていました。

    キャンセル

check解決した方法

0

みなさま回答ありがとうございます。

time_change関数がうまく機能しておらず、想定外の動きをしていました。

if(mb_strlen($time_str) < 4)


この部分で、文字数でなくバイトで判定されていたために条件に合わなくなっていました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

目的地のURLパラメータの渡し方、受け取り方が悪い気がします、
$_POSTは.htaccessなりで値が追加されたり削除されたりソートされたりされ得ます
リクエストしたURLの通りの値が全くそのまま入ってくる保証がありません

順番を保持したいなら配列で値を渡す方が確実かと思います

<input type="text" name="destination[0]"/>
<input type="text" name="destination[1]"/>
<input type="text" name="destination[2]"/>
....
$post=$_POST['destination'];//本番ではちゃんとサニタイズしてください

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/06/29 21:36

    回答ありがとうございます。
    time_change関数がうまく機能しておらず、想定外の動きをしていました。

    キャンセル

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

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る