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

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

ただいまの
回答率

88.80%

phpでのpdoのインサート処理について

解決済

回答 2

投稿 編集

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

退会済みユーザー

前提・実現したいこと

現在YouTube Data APIを使ってJSONを取得し、それを配列に変換後、データベースにインサートするシステムを制作しています。以下は問題の発生しているソースコードを抜粋編集しております。

//APIから情報を取得するfunctionをインクルード
include 'vt-getChannel.php';
error_reporting(E_ALL);
//YouTubeのユーザーキーを設定
$USER_KEY = "ユーザーキー";

//DBへの接続を行う
//DBヘの接続情報が記載されているphpファイルを読み込む
require_once('../~ファイルまでのpath~/database.php');
define('DATABASE_NAME',$database_name);
define('DATABASE_USER',$database_user);
define('DATABASE_PASSWORD',$database_password);
define('DATABASE_HOST',$database_host);
define('PDO_DSN','mysql:dbname=' . DATABASE_NAME .';host=' . DATABASE_HOST);
$pdo = new PDO( PDO_DSN, DATABASE_USER, DATABASE_PASSWORD );
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);

//YouTubeチャンネルのIDを指定する。
$vt_channelId = 'UCNSr_pgMH3in2d0RGtcdEEg';

$video_array = getNewVideoList($USER_KEY, $vt_channelId);

for($i=0; $i<5; $i++){
$video_thumbnail = $video_array['items'][$i]['snippet']['thumbnails']['medium']['url'];
$video_title = $video_array['items'][$i]['snippet']['title'];
$video_date = $video_array['items'][$i]['snippet']["publishedAt"];
$video_summary = $video_array['items'][$i]['snippet']["description"];
$video_id = $video_array['items'][$i]['id']["videoId"];

// ここまで変数に値があることを確認しました

$smt = $pdo -> prepare("insert into at_video (youtube_channel_id, video_thumbnail, video_title, video_date, video_summary, video_id) values (:youtube_channel_id, :video_thumbnail, :video_title, :video_date, :video_summary, :video_id)");
$smt->bindParam(':youtube_channel_id', $vt_channelId, PDO::PARAM_STR);
$smt->bindParam(':video_thumbnail', $video_thumbnail, PDO::PARAM_STR);
$smt->bindParam(':video_title', $video_title, PDO::PARAM_STR);
$smt->bindParam(':video_date', $video_date, PDO::PARAM_STR);
$smt->bindParam(':video_summary', $video_summary, PDO::PARAM_STR);
$smt->bindParam(':video_id', $video_id, PDO::PARAM_STR);
$smt->execute();

$check=$smt->execute();
if($check){
echo '成功!';
}else{
echo '失敗!';
}
var_dump($pdo->errorInfo());
}
}

function getNewVideoList($USER_KEY, $CHANNEL_ID){
//特定チャンネルの最新の動画IDを取得する
$API_BASE_URL_01 = "https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=".$CHANNEL_ID."&order=date&key=".$USER_KEY;
//APIにアクセス、結果を配列にして$arrayに格納
$contents = file_get_contents($API_BASE_URL_01);
$arrays= json_decode($contents, true);
return $arrays;
}

発生している問題・エラーメッセージ

数十件のデータを一度にDBにインサートする際に、for文の中で一部の情報だけインサートされないという問題が発生しました。そのため、ソースコードを切り分け、上記の部分で何かしらの問題が起きているところまでは分かりました。

他のYouTubeチャンネルはこのソースコードで問題なく情報を取得できているのですが、一部のチャンネルだけjsonを取得し、配列に変換、変数への代入も行えているのに、DBにインサートされない状況です。また、$check=$smt->execute();の結果は「失敗」になっており、var_dump($pdo->errorInfo());は00000と空になっています。

誰かわかる方がいらっしゃいましたら、回答をよろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2019/06/03 11:27

    あとできればテーブル定義(CREATE TABLE文が望ましい)もご提示ください。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2019/06/03 11:44

    他の方からの回答で解決することが出来ました。

    今回は回答していただきありがとうございます

    キャンセル

  • m.ts10806

    2019/06/03 11:45

    回答というよりあくまで確認依頼でしたが、解決されたようで何よりです。

    キャンセル

回答 2

checkベストアンサー

+2

$pdo = new PDO( PDO_DSN, DATABASE_USER, DATABASE_PASSWORD );
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);


try (
  $pdo = new PDO( PDO_DSN, DATABASE_USER, DATABASE_PASSWORD, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
  ]);
....
....
}
catch (PDOException $e) {
    echo $e->getMessage();
    exit;
}


などとしないと、エラーが発生してもろくに情報が取れません。
そのうえで、$pdo$smtがFALSEでないことを検証してください。
(var_dump()駆使すれば簡単かと。)

$smt = $pdo -> prepare("insert into at_video (youtube_channel_id, video_thumbnail, video_title, video_date, video_summary, video_id) values (:youtube_channel_id, :video_thumbnail, :video_title, :video_date, :video_summary, :video_id)");
$smt->bindParam(':youtube_channel_id', $vt_channelId, PDO::PARAM_STR);
$smt->bindParam(':video_thumbnail', $video_thumbnail, PDO::PARAM_STR);
$smt->bindParam(':video_title', $video_title, PDO::PARAM_STR);
$smt->bindParam(':video_date', $video_date, PDO::PARAM_STR);
$smt->bindParam(':video_summary', $video_summary, PDO::PARAM_STR);
$smt->bindParam(':video_id', $video_id, PDO::PARAM_STR);
$smt->execute();


$smt = $pdo -> prepare("insert into at_video (youtube_channel_id, video_thumbnail, video_title, video_date, video_summary, video_id) values (:youtube_channel_id, :video_thumbnail, :video_title, :video_date, :video_summary, :video_id)");
$smt->bindValue(':youtube_channel_id', $vt_channelId, PDO::PARAM_STR);
$smt->bindValue(':video_thumbnail', $video_thumbnail, PDO::PARAM_STR);
$smt->bindValue(':video_title', $video_title, PDO::PARAM_STR);
$smt->bindValue(':video_date', $video_date, PDO::PARAM_STR);
$smt->bindValue(':video_summary', $video_summary, PDO::PARAM_STR);
$smt->bindValue(':video_id', $video_id, PDO::PARAM_STR);
$smt->execute();


をお試しを。bindParam()ではなくbindValue()がふさわしい場面かと。

--
追記。
define('PDO_DSN','mysql:dbname=' . DATABASE_NAME .';host=' . DATABASE_HOST . ';charset=utf8mb4');
などとデータベース接続のエンコーディング指定を加えてみると良いかと。
ちなみに、phpからのデータベース接続まわりは
PHPでデータベースに接続するときのまとめ - Qiita
を何度も読み返すことで発見が深まります。おすすめ。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/06/03 11:22

    回答ありがとうざいます。
    try文の部分を回答いただいた形に変更し、bindValue()に変更し実行したところ、以下のようなエラー文が表示されました。

    「Connection failed: SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\xA6\x87 \xE6...' for column 'video_summary' at row 1」

    読んだ感じ、utf8で指定しているテーブルにバイト数の多い文字が入れられたために、エラーを出力していると思うのですが、DBの文字コードを変更するにはphpmyadminから直接変更する形で良いのでしょうか?

    キャンセル

  • 2019/06/03 11:26 編集

    データベース接続時のエンコーディングがあっていない可能性があります。
    define('PDO_DSN','mysql:dbname=' . DATABASE_NAME .';host=' . DATABASE_HOST . ';charset=utf8mb4');
    をお試しください。phpコード自体もutf-8で書いてありますよね?
    ネット検索で「General error: 1366 Incorrect string value」すると関連情報が見つかります。
    絵文字が含まれていると、通常のutf-8では通らない場合も、utf8mb4の指定でなら通ることがあります。

    キャンセル

  • 2019/06/03 11:42

    いただいたコードを入れたところ、問題なく動きました。

    YouTubeから情報を引っ張ってくると絵文字などが入ってくることが多いので、今後はそこも気をつけなければいけないですね。

    この度は迅速で的確な回答ありがとうございます。

    キャンセル

+1

複数の値を一気にいれるということでしょうか?
バルクインサートが良いと思います

insert into tbl(col1,col2・・・) values(?,?・・・),(?,?・・・),・・・


こうなるよう値を流し込むだけです

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/06/03 11:43

    他の方からの回答で解決することが出来ました。

    今回は回答していただきありがとうございます

    キャンセル

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

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

関連した質問

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