こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

csvファイルをMySQLにインポートしたい

phpでcsvファイルをフォルダにアップロードし、これをMySQLにインポートするプログラムを作成しています。
以下のソースを実行したところエラーが発生しました。


-----food.csv----------------------------------------------------------------------

"No","name","price"
"1","うどん","100"
"2","ぱすた","500"
"3","カレー","300"
----------------------------------------------------------------------------------

-----BaseDAO.php------------------------------------------------------------------
<?php

class BaseDAO{
function connect(){
try {
$dsn = "mysql:host=localhost;dbname=food";

$option = array(
// エラーモードを例外スローに設定
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// local ファイルからload可能にする
PDO::MYSQL_ATTR_LOCAL_INFILE => true

);

$user = 'username';
$password = 'password';
$pdo = new PDO($dsn, $user, $password, $option);
$pdo->exec("SET NAMES utf8");
return $pdo;

//var_dump($pdo);

} catch (PDOException $ex) {
print($ex->getMessage());
die("データベース接続に失敗しました");
}
return null;
}

function disconnect($dao){
$dao = null;
}

}
?>
----------------------------------------------------------------------------------

------uploadcsv.php-----------------------------------------------------------------

<?php
require_once 'BaseDAO.php';


//csvファイルのアップロード
if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) {
//「files」という名前のフォルダを同じ階層に設置。ここにCSVファイルをアップロード
if (move_uploaded_file($_FILES["upfile"]["tmp_name"], "files/" . $_FILES["upfile"]["name"])) {
chmod("files/" . $_FILES["upfile"]["name"], 0644);

//fileパス
$file = "files/" .$_FILES["upfile"]["name"];

$sql_src = <<<SQL
LOAD DATA LOCAL INFILE %s INTO TABLE `%s`
CHARACTER SET sjis
fields terminated by ',' enclosed by '"'
lines terminated by '\\r\\n'
IGNORE 1 LINES
SQL;

$table= 'food'; //テーブル名

$inport=new BaseDAO(); //インスタンス作成
$pdo=$inport->connect(); //pdoクラスに接続

$sql = sprintf($sql_src , $pdo->quote($file), $table);

//sql文の実行
$stmt = $pdo->query($sql);


echo "インポートが完了しました!";
//失敗したとき
} else {
echo "ファイルをアップロードできません。";
}
} else {
echo "ファイルが選択されていません。";
}
?>

-----index.html---------------------------------------------------------------------

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>sample</title>
</head>
<body>
<form action="uploadcsv.php" method="POST" enctype="multipart/form-data">
ファイル:<br>
<input type="file" name="upfile" size="30"><br>
<br>
<input type="submit" value="アップロード">
</form>
</body>
</html>

----------------------------------------------------------------------------------

--------foodテーブルを作成するSQL文------------------------------------------------

CREATE TABLE IF NOT EXISTS `food` (
`No` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`price` varchar(50) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

----------------------------------------------------------------------------------


実行したところ以下のエラーが発生しました。
Warning: PDO::query() [pdo.query]: LOAD DATA LOCAL INFILE forbidden in C:\xampp\htdocs\food\uploadcsv.php on line 30

<当方のPC環境>
phpMyAdmin:3.3.9
PHP: 5.3.5
Apache 2.2.17
MySQL 5.5.8
XAMPP version 1.7.4

フォルダ(files)にcsvファイルがアップロードされているところまでは確認できましたが、MySQLにインポートされていないようです。
BaseDAO.php内の「PDO::MYSQL_ATTR_LOCAL_INFILE => true」が効いていないように思えます。
初歩的な質問で凝縮ですが、原因を教えていただきたく存じます。

投稿日時 - 2014-03-03 17:42:56

QNo.8498457

すぐに回答ほしいです

質問者が選んだベストアンサー

xamppでload data local がエラーになるのは知ってましたが、日本語で検索してもでてきませんねぇ。
http://osdir.com/ml/ProfessionalPHPDevelopers/2011-03/msg00043.html
なにやら linux でも同じ問題があるらしい。
→検索キーワード「PDO, mysqlnd bug load」で漸く、、、

https://bugs.php.net/bug.php?id=54158

mysqli では問題ないので pdo_mysql の問題のようです。
どうやら、pdo_mysql driver の再コンパイルが必要らしい。
でもって、php5.4でも配布版では直ってないらしいです。上記ページの最後に以下の記述が!。
>I still seem to have this problem on: PHP 5.4.17-1~precise+1
Ubuntu 12.04

windows での再コンパイルは、Cのコンパイラー持ってないと無理なので
対策1:load だけ、mysqli でやってしまう
対策2:windowsのlocalhost なら、php側ファイルであっても、絶対パスにすれば、mysql serverからも読み込み可能なので、local はずして、実行させる。
emulation mode (オプションの PDO::MYSQL_ATTR_DIRECT_QUERY =>true またはこのキー省略)で実行すればいけます。PDO::MYSQL_ATTR_DIRECT_QUERY =>false にすると、windowsのversionによってはまた違うエラーが出たりして、pdo_mysqlのload文への対応おかしいです。
<?php
// ファイル名を絶対パスにする。$fileに相対パスが入ってるとする。
$file = dirname(__FILE__) .DIRECTORY_SEPARATOR. $file;

参考URL:https://bugs.php.net/bug.php?id=54158

投稿日時 - 2014-03-04 17:28:48

お礼

返信が大変遅くなってしまい申し訳ございません。
mysqli関数での接続と、絶対パスでのsql文実行の両方の方法でコードを修正して実行してみましたが、インポートされませんでした。sql文の中身を試しにechoで出力し、そのsql文をコピーしてmysqlから実行してみたところインポートできました。という事はsql文は正しいようです。そうなるとおっしゃる通りphp側のバグという事になります。

悩み続けましたがやむおえずPHPのバージョン5.4.19とMySQLのバージョン5.5.32にそれぞれバージョンアップ、質問に記載したコードをそのままコピペしただけで実行できました。どうやらバージョンによっては不具合が生じるようです。

ともかく解決しましたので非常に助かりました。ご返信の内容の中には当方のほかのコードの参考になる内容(PDO接続の際のオプション記載について)も含まれていましたのでさっそく修正させていただきました。

ありがとうございました(#^.^#)

投稿日時 - 2014-03-10 23:26:10

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.1

ちょっと疑問なのですが
わざわざmove_uploaded_file()しないで、テンポラリフォルダの中から
csvファイルを取り込んでみては?

投稿日時 - 2014-03-04 11:52:51

お礼

返信が大変おそくなって申し訳ございません。
move_uploaded_file()しないで直接一時フォルダから取り出す方法も試作してみましたが、うまくsql文が実行されませんでした。
結局PHPのバージョンを上げたことで解決いたしました。
一緒に考えていただけて感謝しております。ありがとうございました(*^^*)

投稿日時 - 2014-03-10 23:35:26

あなたにオススメの質問