📄 csv.php
字号:
<?php/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: *//** * File::CSV * * PHP versions 4 and 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category File * @package File * @author Tomas V.V.Cox <cox@idecnet.com> * @author Helgi 辭rmar <dufuz@php.net> * @copyright 2004-2005 The Authors * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: CSV.php,v 1.24 2005/08/09 08:16:02 dufuz Exp $ * @link http://pear.php.net/package/File */require_once 'PEAR.php';require_once 'File.php';/*** File class for handling CSV files (Comma Separated Values), a common format* for exchanging data.** TODO:* - Usage example and Doc* - Use getPointer() in discoverFormat* - Add a line counter for being able to output better error reports* - Store the last error in GLOBALS and add File_CSV::getLastError()** Wish:* - Other methods like readAll(), writeAll(), numFields(), numRows()* - Try to detect if a CSV has header or not in discoverFormat()** Known Bugs:* (they has been analyzed but for the moment the impact in the speed for* properly handle this uncommon cases is too high and won't be supported)* - A field which is composed only by a single quoted separator (ie -> ;";";)* is not handled properly* - When there is exactly one field minus than the expected number and there* is a field with a separator inside, the parser will throw the "wrong count" error** @author Tomas V.V.Cox <cox@idecnet.com>* @author Helgi 辭rmar <dufuz@php.net>* @package File*/class File_CSV{ /** * This raiseError method works in a different way. It will always return * false (an error occurred) but it will call PEAR::raiseError() before * it. If no default PEAR global handler is set, will trigger an error. * * @param string $error The error message * @return bool always false */ function raiseError($error) { // If a default PEAR Error handler is not set trigger the error // XXX Add a PEAR::isSetHandler() method? if ($GLOBALS['_PEAR_default_error_mode'] == PEAR_ERROR_RETURN) { PEAR::raiseError($error, null, PEAR_ERROR_TRIGGER, E_USER_WARNING); } else { PEAR::raiseError($error); } return false; } /** * Checks the configuration given by the user * * @access private * @param string &$error The error will be written here if any * @param array &$conf The configuration assoc array * @return string error Returns a error message */ function _conf(&$error, &$conf) { // check conf if (!is_array($conf)) { return $error = 'Invalid configuration'; } if (!isset($conf['fields']) || !is_numeric($conf['fields'])) { return $error = 'The number of fields must be numeric (the "fields" key)'; } if (isset($conf['sep'])) { if (strlen($conf['sep']) != 1) { return $error = 'Separator can only be one char'; } } elseif ($conf['fields'] > 1) { return $error = 'Missing separator (the "sep" key)'; } if (isset($conf['quote'])) { if (strlen($conf['quote']) != 1) { return $error = 'The quote char must be one char (the "quote" key)'; } } else { $conf['quote'] = null; } if (!isset($conf['crlf'])) { $conf['crlf'] = "\n"; } if (!isset($conf['eol2unix'])) { $conf['eol2unix'] = true; } } /** * Return or create the file descriptor associated with a file * * @param string $file The name of the file * @param array &$conf The configuration * @param string $mode The open node (ex: FILE_MODE_READ or FILE_MODE_WRITE) * @param boolean $reset if passed as true and resource for the file exists * than the file pointer will be moved to the beginning * * @return mixed A file resource or false */ function getPointer($file, &$conf, $mode = FILE_MODE_READ, $reset = false) { static $resources = array(); static $config; if (isset($resources[$file])) { $conf = $config; if ($reset) { fseek($resources[$file], 0); } return $resources[$file]; } File_CSV::_conf($error, $conf); if ($error) { return File_CSV::raiseError($error); } $config = $conf; PEAR::pushErrorHandling(PEAR_ERROR_RETURN); $fp = &File::_getFilePointer($file, $mode); PEAR::popErrorHandling(); if (PEAR::isError($fp)) { return File_CSV::raiseError($fp); } $resources[$file] = $fp; if ($mode == FILE_MODE_READ && !empty($conf['header'])) { if (!File_CSV::read($file, $conf)) { return false; } } return $fp; } /** * Unquote data * * @param string $field The data to unquote * @param string $quote The quote char * @return string the unquoted data */ function unquote($field, $quote) { // Trim first the string. $field = trim($field); $quote = trim($quote); // Incase null fields (form: ;;) if (!strlen($field)) { return $field; } if ($quote && $field{0} == $quote && $field{strlen($field)-1} == $quote) { return substr($field, 1, -1); } return $field; } /** * Reads a row of data as an array from a CSV file. It's able to * read memo fields with multiline data. * * @param string $file The filename where to write the data * @param array &$conf The configuration of the dest CSV * * @return mixed Array with the data read or false on error/no more data */ function readQuoted($file, &$conf) { if (!$fp = File_CSV::getPointer($file, $conf, FILE_MODE_READ)) { return false; } $buff = $c = ''; $ret = array(); $i = 1; $in_quote = false; $quote = $conf['quote']; $f = $conf['fields']; $eol2unix = $conf['eol2unix']; while (($ch = fgetc($fp)) !== false) { $prev = $c; $c = $ch; // Common case if ($c != $quote && $c != $conf['sep'] && $c != "\n" && $c != "\r") { $buff .= $c; continue; } // Start quote. if ($quote && $c == $quote && ($prev == $conf['sep'] || $prev == "\n" || $prev === null || $prev == "\r" || $prev == '')) { $in_quote = true; } if ($in_quote) { // When ends quote if ($c == $conf['sep'] && $prev == $conf['quote']) { $in_quote = false; } elseif ($c == "\n" || $c == "\r") { $sub = ($prev == "\r") ? 2 : 1; if ((strlen($buff) >= $sub) && ($buff{strlen($buff) - $sub} == $quote)) { $in_quote = false; } } } if (!$in_quote && ($c == $conf['sep'] || $c == "\n" || $c == "\r") && $prev != '') { // More fields than expected if (($c == $conf['sep']) && ((count($ret) + 1) == $f)) { // Seek the pointer into linebreak character. while (true) { $c = fgetc($fp); if ($c == "\n" || $c == "\r") { break; } } // Insert last field value. $ret[] = File_CSV::unquote($buff, $quote); return $ret; } // Less fields than expected if (($c == "\n" || $c == "\r") && ($i != $f)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -