mirror of
https://github.com/parsecsv/parsecsv-for-php.git
synced 2026-02-19 08:36:39 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20a6a9d1b1 | ||
|
|
70366e3085 | ||
|
|
2dfd35b988 | ||
|
|
ae00f949f0 | ||
|
|
4e76da5eff | ||
|
|
7762e71316 |
@@ -1,3 +1,81 @@
|
|||||||
|
parseCSV 0.4.1 beta
|
||||||
|
-----------------------------------
|
||||||
|
Date: 29-May-2008
|
||||||
|
|
||||||
|
- Fixed a small bug in how the output() method
|
||||||
|
handles input data.
|
||||||
|
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
parseCSV 0.4 beta
|
||||||
|
-----------------------------------
|
||||||
|
Date: 11-Apr-2008
|
||||||
|
|
||||||
|
- Error reporting for files/data which is corrupt
|
||||||
|
or has formatting errors like using double
|
||||||
|
quotes in a field without enclosing quotes. Or
|
||||||
|
not escaping double quotes with a second one.
|
||||||
|
|
||||||
|
- parse() method does not require input anymore
|
||||||
|
if the "$object->file" property has been set.
|
||||||
|
|
||||||
|
I'm calling this a beta release due to the heavy
|
||||||
|
modifications to the core parsing logic required
|
||||||
|
for error reporting to work. I have tested the
|
||||||
|
new code quite extensively, I'm fairly confident
|
||||||
|
that it still parses exactly as it always has.
|
||||||
|
|
||||||
|
The second reason I'm calling it a beta release
|
||||||
|
is cause I'm sure the error reporting code will
|
||||||
|
need more refinements and tweaks to detect more
|
||||||
|
types of errors, as it's only picking two types
|
||||||
|
or syntax errors right now. However, it seems
|
||||||
|
these two are the most common errors that you
|
||||||
|
would be likely to come across.
|
||||||
|
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
parseCSV 0.3.2
|
||||||
|
-----------------------------------
|
||||||
|
Date: 1-Apr-2008
|
||||||
|
|
||||||
|
This is primarily a bug-fix release for a critical
|
||||||
|
bug which was brought to my attention.
|
||||||
|
|
||||||
|
- Fixed a critical bug in conditions parsing which
|
||||||
|
would generate corrupt matching patterns causing
|
||||||
|
the condition(s) to not work at all in some
|
||||||
|
situations.
|
||||||
|
|
||||||
|
- Fixed a small code error which would cause PHP to
|
||||||
|
generate a invalid offset notice when zero length
|
||||||
|
values were fed into the unparse() method to
|
||||||
|
generate CSV data from an array.
|
||||||
|
|
||||||
|
Notice: If you have been using the "parsecsv-stable"
|
||||||
|
branch as an external in any of your projects,
|
||||||
|
please use the "stable/parsecsv" branch from this
|
||||||
|
point on as I will eventually remove the former due
|
||||||
|
to it's stupid naming.
|
||||||
|
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
parseCSV 0.3.1
|
||||||
|
-----------------------------------
|
||||||
|
Date: 1-Sep-2007
|
||||||
|
|
||||||
|
- Small change to default output settings to
|
||||||
|
conform with RFC 4180 (http://rfc.net/rfc4180.html).
|
||||||
|
Only the LF (line feed) character was used
|
||||||
|
by default to separate rows, rather than
|
||||||
|
CRLF (carriage return & line feed).
|
||||||
|
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
|
||||||
parseCSV 0.3.0
|
parseCSV 0.3.0
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
Date: 9-Aug-2007
|
Date: 9-Aug-2007
|
||||||
@@ -18,6 +96,9 @@ Date: 9-Aug-2007
|
|||||||
- Minor changes and optimizations, and a few
|
- Minor changes and optimizations, and a few
|
||||||
spelling corrections. Oops :)
|
spelling corrections. Oops :)
|
||||||
|
|
||||||
|
- Included more complex code examples in the
|
||||||
|
parseCSV download.
|
||||||
|
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
rating,title,author,type,asin,tags,review
|
rating,title,author,type,asin,tags,review
|
||||||
0,The Killing Kind,John Connolly,Book,0340771224,,i still haven't had time to read this one...
|
0,The Killing Kind,John Connolly,Book,0340771224,,i still haven't had time to read this one...
|
||||||
0,The Third Secret,Steve Berry,Book,0340899263,,need to find time to read this book
|
0,The Third Secret,Steve Berry,Book,0340899263,,need to find time to read this book
|
||||||
3,The Last Templar,Raymond Khoury,Book,0752880705,,
|
3,The Last Templar,Raymond Khoury,Book,0752880705,,
|
||||||
5,The Traveller,John Twelve Hawks,Book,059305430X,,
|
5,The Traveller,John Twelve Hawks,Book,059305430X,,
|
||||||
4,Crisis Four,Andy Mcnab,Book,0345428080,,
|
4,Crisis Four,Andy Mcnab,Book,0345428080,,
|
||||||
5,Prey,Michael Crichton,Book,0007154534,,
|
5,Prey,Michael Crichton,Book,0007154534,,
|
||||||
3,The Broker (Paperback),John Grisham,Book,0440241588,book johngrisham,"good book, but is slow in the middle"
|
3,The Broker (Paperback),John Grisham,Book,0440241588,book johngrisham,"good book, but is slow in the middle"
|
||||||
3,Without Blood (Paperback),Alessandro Baricco,Book,1841955744,,
|
3,Without Blood (Paperback),Alessandro Baricco,Book,1841955744,,
|
||||||
5,State of Fear (Paperback),Michael Crichton,Book,0061015733,,
|
5,State of Fear (Paperback),Michael Crichton,Book,0061015733,,
|
||||||
4,The Rule of Four (Paperback),Ian Caldwell,Book,0099451956,book bestseller,
|
4,The Rule of Four (Paperback),Ian Caldwell,Book,0099451956,book bestseller,
|
||||||
4,Deception Point (Paperback),Dan Brown,Book,0671027387,book danbrown bestseller,
|
4,Deception Point (Paperback),Dan Brown,Book,0671027387,book danbrown bestseller,
|
||||||
5,Digital Fortress : A Thriller (Mass Market Paperback),Dan Brown,Book,0312995423,book danbrown bestseller,
|
5,Digital Fortress : A Thriller (Mass Market Paperback),Dan Brown,Book,0312995423,book danbrown bestseller,
|
||||||
5,Angels & Demons (Mass Market Paperback),Dan Brown,Book,0671027360,book danbrown bestseller,
|
5,Angels & Demons (Mass Market Paperback),Dan Brown,Book,0671027360,book danbrown bestseller,
|
||||||
4,The Da Vinci Code (Hardcover),Dan Brown," Book ",0385504209,book movie danbrown bestseller davinci,
|
4,The Da Vinci Code (Hardcover),Dan Brown," Book ",0385504209,book movie danbrown bestseller davinci,
|
||||||
|
@@ -13,7 +13,11 @@ $csv = new parseCSV();
|
|||||||
# Parse '_books.csv' using automatic delimiter detection...
|
# Parse '_books.csv' using automatic delimiter detection...
|
||||||
$csv->auto('_books.csv');
|
$csv->auto('_books.csv');
|
||||||
|
|
||||||
# ...or if you know the delimiter, use the parse() function.
|
# ...or if you know the delimiter, set the delimiter character
|
||||||
|
# if its not the default comma...
|
||||||
|
// $csv->delimiter = "\t"; # tab delimited
|
||||||
|
|
||||||
|
# ...and then use the parse() function.
|
||||||
// $csv->parse('_books.csv');
|
// $csv->parse('_books.csv');
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
132
parsecsv.lib.php
132
parsecsv.lib.php
@@ -4,7 +4,7 @@ class parseCSV {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
Class: parseCSV v0.3.0
|
Class: parseCSV v0.4.1 beta
|
||||||
http://code.google.com/p/parsecsv-for-php/
|
http://code.google.com/p/parsecsv-for-php/
|
||||||
|
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ class parseCSV {
|
|||||||
var $output_encoding = 'ISO-8859-1';
|
var $output_encoding = 'ISO-8859-1';
|
||||||
|
|
||||||
# used by unparse(), save(), and output() functions
|
# used by unparse(), save(), and output() functions
|
||||||
var $linefeed = "\n";
|
var $linefeed = "\r\n";
|
||||||
|
|
||||||
# only used by output() function
|
# only used by output() function
|
||||||
var $output_delimiter = ',';
|
var $output_delimiter = ',';
|
||||||
@@ -140,6 +140,19 @@ class parseCSV {
|
|||||||
# loaded file contents
|
# loaded file contents
|
||||||
var $file_data;
|
var $file_data;
|
||||||
|
|
||||||
|
# error while parsing input data
|
||||||
|
# 0 = No errors found. Everything should be fine :)
|
||||||
|
# 1 = Hopefully correctable syntax error was found.
|
||||||
|
# 2 = Enclosure character (double quote by default)
|
||||||
|
# was found in non-enclosed field. This means
|
||||||
|
# the file is either corrupt, or does not
|
||||||
|
# standard CSV formatting. Please validate
|
||||||
|
# the parsed data yourself.
|
||||||
|
var $error = 0;
|
||||||
|
|
||||||
|
# detailed error info
|
||||||
|
var $error_info = array();
|
||||||
|
|
||||||
# array of field values in data parsed
|
# array of field values in data parsed
|
||||||
var $titles = array();
|
var $titles = array();
|
||||||
|
|
||||||
@@ -170,6 +183,7 @@ class parseCSV {
|
|||||||
* @return nothing
|
* @return nothing
|
||||||
*/
|
*/
|
||||||
function parse ($input = null, $offset = null, $limit = null, $conditions = null) {
|
function parse ($input = null, $offset = null, $limit = null, $conditions = null) {
|
||||||
|
if ( $input === null ) $input = $this->file;
|
||||||
if ( !empty($input) ) {
|
if ( !empty($input) ) {
|
||||||
if ( $offset !== null ) $this->offset = $offset;
|
if ( $offset !== null ) $this->offset = $offset;
|
||||||
if ( $limit !== null ) $this->limit = $limit;
|
if ( $limit !== null ) $this->limit = $limit;
|
||||||
@@ -272,13 +286,13 @@ class parseCSV {
|
|||||||
$pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ;
|
$pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ;
|
||||||
|
|
||||||
// open and closing quotes
|
// open and closing quotes
|
||||||
if ( $ch == $enclosure && (!$enclosed || $nch != $enclosure) ) {
|
if ( $ch == $enclosure ) {
|
||||||
$enclosed = ( $enclosed ) ? false : true ;
|
if ( !$enclosed || $nch != $enclosure ) {
|
||||||
|
$enclosed = ( $enclosed ) ? false : true ;
|
||||||
// inline quotes
|
} elseif ( $enclosed ) {
|
||||||
} elseif ( $ch == $enclosure && $enclosed ) {
|
$i++;
|
||||||
$i++;
|
}
|
||||||
|
|
||||||
// end of row
|
// end of row
|
||||||
} elseif ( ($ch == "\n" && $pch != "\r" || $ch == "\r") && !$enclosed ) {
|
} elseif ( ($ch == "\n" && $pch != "\r" || $ch == "\r") && !$enclosed ) {
|
||||||
if ( $n >= $search_depth ) {
|
if ( $n >= $search_depth ) {
|
||||||
@@ -311,13 +325,12 @@ class parseCSV {
|
|||||||
|
|
||||||
// capture most probable delimiter
|
// capture most probable delimiter
|
||||||
ksort($filtered);
|
ksort($filtered);
|
||||||
$delimiter = reset($filtered);
|
$this->delimiter = reset($filtered);
|
||||||
$this->delimiter = $delimiter;
|
|
||||||
|
|
||||||
// parse data
|
// parse data
|
||||||
if ( $parse ) $this->data = $this->parse_string();
|
if ( $parse ) $this->data = $this->parse_string();
|
||||||
|
|
||||||
return $delimiter;
|
return $this->delimiter;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,6 +362,8 @@ class parseCSV {
|
|||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$white_spaces = str_replace($this->delimiter, '', " \t\x0B\0");
|
||||||
|
|
||||||
$rows = array();
|
$rows = array();
|
||||||
$row = array();
|
$row = array();
|
||||||
$row_count = 0;
|
$row_count = 0;
|
||||||
@@ -365,24 +380,68 @@ class parseCSV {
|
|||||||
$nch = ( isset($data{$i+1}) ) ? $data{$i+1} : false ;
|
$nch = ( isset($data{$i+1}) ) ? $data{$i+1} : false ;
|
||||||
$pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ;
|
$pch = ( isset($data{$i-1}) ) ? $data{$i-1} : false ;
|
||||||
|
|
||||||
// open and closing quotes
|
// open/close quotes, and inline quotes
|
||||||
if ( $ch == $this->enclosure && (!$enclosed || $nch != $this->enclosure) ) {
|
if ( $ch == $this->enclosure ) {
|
||||||
$enclosed = ( $enclosed ) ? false : true ;
|
if ( !$enclosed ) {
|
||||||
if ( $enclosed ) $was_enclosed = true;
|
if ( ltrim($current, $white_spaces) == '' ) {
|
||||||
|
$enclosed = true;
|
||||||
// inline quotes
|
$was_enclosed = true;
|
||||||
} elseif ( $ch == $this->enclosure && $enclosed ) {
|
} else {
|
||||||
$current .= $ch;
|
$this->error = 2;
|
||||||
$i++;
|
$error_row = count($rows) + 1;
|
||||||
|
$error_col = $col + 1;
|
||||||
|
if ( !isset($this->error_info[$error_row.'-'.$error_col]) ) {
|
||||||
|
$this->error_info[$error_row.'-'.$error_col] = array(
|
||||||
|
'type' => 2,
|
||||||
|
'info' => 'Syntax error found on row '.$error_row.'. Non-enclosed fields can not contain double-quotes.',
|
||||||
|
'row' => $error_row,
|
||||||
|
'field' => $error_col,
|
||||||
|
'field_name' => (!empty($head[$col])) ? $head[$col] : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$current .= $ch;
|
||||||
|
}
|
||||||
|
} elseif ($nch == $this->enclosure) {
|
||||||
|
$current .= $ch;
|
||||||
|
$i++;
|
||||||
|
} elseif ( $nch != $this->delimiter && $nch != "\r" && $nch != "\n" ) {
|
||||||
|
for ( $x=($i+1); isset($data{$x}) && ltrim($data{$x}, $white_spaces) == ''; $x++ ) {}
|
||||||
|
if ( $data{$x} == $this->delimiter ) {
|
||||||
|
$enclosed = false;
|
||||||
|
$i = $x;
|
||||||
|
} else {
|
||||||
|
if ( $this->error < 1 ) {
|
||||||
|
$this->error = 1;
|
||||||
|
}
|
||||||
|
$error_row = count($rows) + 1;
|
||||||
|
$error_col = $col + 1;
|
||||||
|
if ( !isset($this->error_info[$error_row.'-'.$error_col]) ) {
|
||||||
|
$this->error_info[$error_row.'-'.$error_col] = array(
|
||||||
|
'type' => 1,
|
||||||
|
'info' =>
|
||||||
|
'Syntax error found on row '.(count($rows) + 1).'. '.
|
||||||
|
'A single double-quote was found within an enclosed string. '.
|
||||||
|
'Enclosed double-quotes must be escaped with a second double-quote.',
|
||||||
|
'row' => count($rows) + 1,
|
||||||
|
'field' => $col + 1,
|
||||||
|
'field_name' => (!empty($head[$col])) ? $head[$col] : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$current .= $ch;
|
||||||
|
$enclosed = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$enclosed = false;
|
||||||
|
}
|
||||||
|
|
||||||
// end of field/row
|
// end of field/row
|
||||||
} elseif ( ($ch == $this->delimiter || ($ch == "\n" && $pch != "\r") || $ch == "\r") && !$enclosed ) {
|
} elseif ( ($ch == $this->delimiter || $ch == "\n" || $ch == "\r") && !$enclosed ) {
|
||||||
if ( !$was_enclosed ) $current = trim($current);
|
|
||||||
$key = ( !empty($head[$col]) ) ? $head[$col] : $col ;
|
$key = ( !empty($head[$col]) ) ? $head[$col] : $col ;
|
||||||
$row[$key] = $current;
|
$row[$key] = ( $was_enclosed ) ? $current : trim($current) ;
|
||||||
$current = '';
|
$current = '';
|
||||||
|
$was_enclosed = false;
|
||||||
$col++;
|
$col++;
|
||||||
|
|
||||||
// end of row
|
// end of row
|
||||||
if ( $ch == "\n" || $ch == "\r" ) {
|
if ( $ch == "\n" || $ch == "\r" ) {
|
||||||
if ( $this->_validate_offset($row_count) && $this->_validate_row_conditions($row, $this->conditions) ) {
|
if ( $this->_validate_offset($row_count) && $this->_validate_row_conditions($row, $this->conditions) ) {
|
||||||
@@ -405,6 +464,7 @@ class parseCSV {
|
|||||||
if ( $this->sort_by === null && $this->limit !== null && count($rows) == $this->limit ) {
|
if ( $this->sort_by === null && $this->limit !== null && count($rows) == $this->limit ) {
|
||||||
$i = $strlen;
|
$i = $strlen;
|
||||||
}
|
}
|
||||||
|
if ( $ch == "\r" && $nch == "\n" ) $i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// append character to current field
|
// append character to current field
|
||||||
@@ -441,7 +501,7 @@ class parseCSV {
|
|||||||
$entry = array();
|
$entry = array();
|
||||||
|
|
||||||
// create heading
|
// create heading
|
||||||
if ( $this->heading && !$append ) {
|
if ( $this->heading && !$append && !empty($fields) ) {
|
||||||
foreach( $fields as $key => $value ) {
|
foreach( $fields as $key => $value ) {
|
||||||
$entry[] = $this->_enclose_value($value);
|
$entry[] = $this->_enclose_value($value);
|
||||||
}
|
}
|
||||||
@@ -503,11 +563,11 @@ class parseCSV {
|
|||||||
function _validate_row_conditions ($row = array(), $conditions = null) {
|
function _validate_row_conditions ($row = array(), $conditions = null) {
|
||||||
if ( !empty($row) ) {
|
if ( !empty($row) ) {
|
||||||
if ( !empty($conditions) ) {
|
if ( !empty($conditions) ) {
|
||||||
$conditions = (strpos($conditions, 'OR') !== false) ? explode('OR', $conditions) : array($conditions) ;
|
$conditions = (strpos($conditions, ' OR ') !== false) ? explode(' OR ', $conditions) : array($conditions) ;
|
||||||
$or = '';
|
$or = '';
|
||||||
foreach( $conditions as $key => $value ) {
|
foreach( $conditions as $key => $value ) {
|
||||||
if ( strpos($value, 'AND') !== false ) {
|
if ( strpos($value, ' AND ') !== false ) {
|
||||||
$value = explode('AND', $value);
|
$value = explode(' AND ', $value);
|
||||||
$and = '';
|
$and = '';
|
||||||
foreach( $value as $k => $v ) {
|
foreach( $value as $k => $v ) {
|
||||||
$and .= $this->_validate_row_condition($row, $v);
|
$and .= $this->_validate_row_condition($row, $v);
|
||||||
@@ -601,11 +661,13 @@ class parseCSV {
|
|||||||
* @return Processed value
|
* @return Processed value
|
||||||
*/
|
*/
|
||||||
function _enclose_value ($value = null) {
|
function _enclose_value ($value = null) {
|
||||||
$delimiter = preg_quote($this->delimiter, '/');
|
if ( $value !== null && $value != '' ) {
|
||||||
$enclosure = preg_quote($this->enclosure, '/');
|
$delimiter = preg_quote($this->delimiter, '/');
|
||||||
if ( preg_match("/".$delimiter."|".$enclosure."|\n|\r/i", $value) || ($value{0} == ' ' || substr($value, -1) == ' ') ) {
|
$enclosure = preg_quote($this->enclosure, '/');
|
||||||
$value = str_replace($this->enclosure, $this->enclosure.$this->enclosure, $value);
|
if ( preg_match("/".$delimiter."|".$enclosure."|\n|\r/i", $value) || ($value{0} == ' ' || substr($value, -1) == ' ') ) {
|
||||||
$value = $this->enclosure.$value.$this->enclosure;
|
$value = str_replace($this->enclosure, $this->enclosure.$this->enclosure, $value);
|
||||||
|
$value = $this->enclosure.$value.$this->enclosure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user