Skip to content

Instantly share code, notes, and snippets.

@yano3nora
Last active July 1, 2017 11:48
Show Gist options
  • Save yano3nora/612be0f7901e3206db8751d58de3a75d to your computer and use it in GitHub Desktop.
Save yano3nora/612be0f7901e3206db8751d58de3a75d to your computer and use it in GitHub Desktop.
[php: SplFileInfo/SplFileObject] import / export csv using SplFileObject. #php #cakephp

what's ?

PHPの標準組込クラスとして SplFileObject というのがあり、ファイル(主にテキストファイル)をどうこうするのに向いているそうな。 SplFileInfo を継承しているのでファイル情報もこいつからとれる。spl (sqlぢゃないよ) は Standard PHP Library の略。

refs


how to use

notice

律儀なやつなのでちゃんと面倒見ること

最終行の改行や空行もちゃあんと認識して登録する真面目クンなので、そのあたりはこっちで教えてあげる。

SJIS-winなんて消えてなくなればいいね

fgetでもこいつでもやっぱりSJIS形式のCSVは扱いに困る。ループ中で mb_convert_encoding() するのも良いが、稀にうまくいかない。読み取り前にアップロードされたファイルを一度全てUTF8にコンバートしてからごにょるのが楽。

<?php
/**
* # TIPS
* ## touch() -> permission denied
* http://www.iwaking.com/20121210/740/
* ------------------------------------ */
App::uses('Component', 'Controller');
/**
* upload & download file handler class
* @category App\Controller\Component
* @var Controller $controller
* @var Request $request
* @var string $encoding
* @var string $decoding
*/
class CsvComponent extends Component {
public $controller;
public $request;
private $encoding = ENCODING;
private $decoding = DECODING;
// before 'beforeFilter'
public function initialize(Controller $controller) {
}
// after 'beforeFilter'
public function startup(Controller $controller) {
$this->controller = $controller;
$this->request = $controller->request;
}
// before 'render'
public function beforeRender(Controller $controller) {
}
// before exit
public function shutdown(Controller $controller) {
}
// before redirect (redirect would canceled when return false from this)
public function beforeRedirect(Controller $controller, $url, $status=null, $exit=true) {
}
/**
* import csv file with encoding to $this->encoding
* @param str $prefix
* @param array $file (e.g.) $this->request->data('User.upload_file')
* @param bool $useHeader (remove first row perhaps header)
* @return array $csv (on success)
* @return bool false (on failure)
* @throws Exception
*/
public function csvImportWithEncoding($prefix, $file, $useHeader=false) {
$csv = array(); //init
if (is_uploaded_file($file['tmp_name']) && pathinfo($file['name'], PATHINFO_EXTENSION) == 'csv') {
$fileName = UPLOAD_DIR.$prefix.'_'.$this->controller->name.'_'.session_id().'.csv';
move_uploaded_file($file['tmp_name'], $fileName);
$rawFile = file_get_contents($fileName);
$encodedFile = mb_convert_encoding($rawFile, $this->encoding, $this->decoding);
file_put_contents($fileName, $encodedFile);
if (!file_exists($fileName)) throw new Exception('ファイルエンコードに失敗しました。');
$fileObj = new SplFileObject($fileName);
$fileObj->setFlags(SplFileObject::READ_CSV);
$fileObj->setCsvControl(",", "\n"); //delimiter
$isAtFirst = true;
foreach ($fileObj as $line) {
if ($isAtFirst && !$useHeader) $isAtFirst = false; continue;
if (is_null($line[0])) continue;
$csv[] = $line;
}
if (!$csv) throw new Exception('ファイル読み取りに失敗しました。データを確認してください。');
return $csv;
} else {
throw new Exception('ファイルアップロードに失敗しました。形式がCSVであるかを確認してください。');
return false;
}
}
/**
* export csv file with encoding to $this->encoding
* @param str $prefix
* @param array $data
* @param array $header
* @return file readfile($filePath)
* @throws Exception
*/
public function csvExportWithEncoding($filename, $data, $header) {
$filePath = DOWNLOAD_DIR.$filename.'.csv';
// encoding
mb_convert_variables($this->decoding, $this->encoding, $header);
mb_convert_variables($this->decoding, $this->encoding, $data);
// create csv file
if (!touch($filePath)) throw new Exception('CSV一時ファイル生成に失敗しました。');
$fileObj = new SplFileObject($filePath, 'w');
if (array_depth($header) >= 2) {
foreach ((array)$header as $headerLine) {
$fileObj->fputcsv($headerLine);
}
} else {
$fileObj->fputcsv($header);
}
foreach ((array)$data as $line) {
$fileObj->fputcsv($line);
}
// print csv file
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); // required for certain browsers
header("Content-Transfer-Encoding: binary");
header("Content-Disposition: attachment; filename=".basename($filePath));
header("Content-Type: application/force-download");
return readfile($filePath);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment