I am generating and exporting a CSV through PHP and after some modifications from my team, now it results that inside a column, double quotation marks are being generated.
I generate it through my terminal by executing this Shell script with the CakePHP Console.
/var/www/mysite.new/trunk/app/Console/cake Csv mysite.uk
The problem is that I already tried many techniques to strip them off such as: stripslashes(), str_replace(), trim()
On my last modification, I tried to apply the str_replace function.
foreach ($persons_csv as $person_csv){
/* The part where I get the data for stripping off the quotation marks */
$mail = $person_csv['Person']['email'];
$name = str_replace('"', '', $person_csv['Person']['name']);
$surname = str_replace('"', '', $person_csv['Person']['surname']);
/* REST OF THE CODE */
}
Nevertheless, it only happens to surnames and names that have more than one word in which the quotations marks are being generated.
Surnames and names that are consisting of one word, they appear to be fine.
Still, there are some anomalies probably inside names that have whitespace and therefore double quotations marks are being generated again. I am not quite sure why this is ocurring.
I can attach you two screenshots so you can have a better understanding of the problem.
If you have any idea of what it might be, it would be really appreciating.
This is the rest of my code in which I am generating the CSV.
private function addRow($row) {
$rows_deleted = 0;
if (!empty($row)){
fputcsv($this->buffer, $row, $this->delimiter, $this->enclosure);
} else {
return false;
}
}
private function renderHeaders() {
header("Content-type:application/vnd.ms-excel");
header("Content-disposition:attachment;filename=" . $this->filename);
}
private function setFilename($filename) {
$this->filename = $filename;
if (strtolower(substr($this->filename, -4)) != '.csv') {
$this->filename .= '.csv';
}
}
private function render($filename = true, $to_encoding = null, $from_encoding = "auto") {
if(PAIS) {
if ($filename) {
if (is_string($filename)) {
$this->setFilename($filename);
}
$this->renderHeaders();
}
rewind($this->buffer);
$output = stream_get_contents($this->buffer);
$url = '/var/www/mysite.new/trunk/' .'app'.DS.'webroot'.DS.'csv'.DS.PAIS.DS.$this->filename;
$gestor = fopen($url, "w+") or die("Unable to open file");
if(file_exists($url)){
file_put_contents($url, $output);
chmod($url, 0777);
fclose($gestor);
} else {
return false;
}
} else {
return false;
}
}
public function csv_persons($persons_csv) {
$this->array_final = [self::NAME, self::SURNAME];
date_default_timezone_get('Europe/Madrid');
$d = date("Ymd");
$this->addRow($this->array_final);
foreach ($persons_csv as $person_csv){
$name = str_replace('"', '', $person_csv['Person']['name']);
$surname = str_replace('"', '', $person_csv['Person']['surname']);
$apos = ''';
$pos = strpos($surname, $apos);
if($pos !== false) {
$surname = str_replace(''', '\'', $surname);
}
$arr = array();
$arr[$this->getArrayKeyIndex($this->array_final, self::NAME)] = $name;
$arr[$this->getArrayKeyIndex($this->array_final, self::SURNAME)] = $surname;
$this->addRow($arr);
}
$filename = 'PERSON_PROFILE_' . $d;
$this->render($filename);
}
Thanks
Instead of using fputcsv, try implode.
Ref: https://www.php.net/manual/en/function.implode.php
Update 1: You have to be sure that your value does not contain , (comma)
Update 2: If you are concern with the idea about that quoted text will be problem for your CSV datasheet, than you need to know that CSV is designed to that if there is any space between the value. So you don't have to worry about that. Any CSV parser will understand the quoted values properly.
Related
I'm trying to build a regular expression in php. I tested it here https://regex101.com/ and it works fine, but that was before I knew I'd have to implement it in php and it adds backslashes where not needed.
Here's my code:
$datePattern = "\[((19|20)\d\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\]";
$tag = "[a-z]+(?:-[a-z]+)*";
$regroupmentPattern = "\[($tag)?\]";
$taglistPattern = "\[((?:$tag)?(?:;(?:$tag))*)\]";
$countryPattern = "\[([a-z]{2})\]";
$freePattern = "\[([^\[\]]*)\]";
$extensionPattern = "\.(jpg|png)";
$repetitionPattern = "(?:\(\d+\))?";
$fullPattern = "/^$datePattern$regroupmentPattern$taglistPattern$countryPattern$freePattern$freePattern$extensionPattern$repetitionPattern$/";
Here is what I want :
^\[((19|20)\d\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\]\[([a-z]+(?:-[a-z]+)*)?\]\[((?:[a-z]+(?:-[a-z]+)*)?(?:;(?:[a-z]+(?:-[a-z]+)*))*)\]\[([a-z]{2})\]\[([^\[\]]*)\]\[([^\[\]]*)\](?:\(\d+\))?\.(jpg|png)$
And here's what I get :
"\"\\/^\\\\[((19|20)\\\\d\\\\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\\\\]\\\\[([a-z]+(?:-[a-z]+)*)?\\\\]\\\\[((?:[a-z]+(?:-[a-z]+)*)?(?:;(?:[a-z]+(?:-[a-z]+)*))*)\\\\]\\\\[([a-z]{2})\\\\]\\\\[([^\\\\[\\\\]]*)\\\\]\\\\[([^\\\\[\\\\]]*)\\\\]\\\\.(jpg|png)(?:\\\\(\\\\d+\\\\))?$\\/\""
I assume there must be some sort of escape function, I tried preg_quote but it added yet even more backslashes.
Btw here's my full code:
<?php
class Gallery {
// Name of the gallery, used to build folder path
private $name;
function __construct($name) {
$this->name = $name;
}
/*
* Returns the list of file names in a gallery folder,
* or false if the folder doesn't exist
*/
public function getFileNames() {
$path = "../../gallery/$this->name";
if (is_dir($path)) {
$allFileNamesArray = scandir($path, SCANDIR_SORT_ASCENDING);
$filteredFileNamesArray = array();
// Building regular expression
$datePattern = "\[((19|20)\d\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\]";
$tag = "[a-z]+(?:-[a-z]+)*";
$regroupmentPattern = "\[($tag)?\]";
$taglistPattern = "\[((?:$tag)?(?:;(?:$tag))*)\]";
$countryPattern = "\[([a-z]{2})\]";
$freePattern = "\[([^\[\]]*)\]";
$extensionPattern = "\.(jpg|png)";
$repetitionPattern = "(?:\(\d+\))?";
$fullPattern = "/^$datePattern$regroupmentPattern$taglistPattern$countryPattern$freePattern$freePattern$extensionPattern$repetitionPattern$/";
foreach ($allFileNamesArray as $fileName) {
$matches = array();
if (preg_match($fullPattern, $fileName, $matches, PREG_UNMATCHED_AS_NULL)) {
$filteredFileNamesArray[] = $fileName;
}
var_dump($matches);
}
return json_encode($fullPattern);
}
else {
return false;
}
}
}
?>
(Here I returned fullPattern istead of filteredFileNamesArray for debugging purpose)
You swapped $repetitionPattern and $extensionPattern.
Use
$fullPattern = "/^$datePattern$regroupmentPattern$taglistPattern$countryPattern$freePattern$freePattern$repetitionPattern$extensionPattern$/";
It will result in
^\[((19|20)\d\d)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])\]\[([a-z]+(?:-[a-z]+)*)?\]\[((?:[a-z]+(?:-[a-z]+)*)?(?:;(?:[a-z]+(?:-[a-z]+)*))*)\]\[([a-z]{2})\]\[([^\[\]]*)\]\[([^\[\]]*)\](?:\(\d+\))?\.(jpg|png)$ pattern.
See the regex demo online.
I have a SQL file which i created from another database (named as test) on my localhost and now i want to insert this data into another database ( named as server_db) via PHP Script .
I tried and my PHP Script is working fine and creating the tables into server_db database.
But values in those tables are not inserting ..... Please Help
My PHP Code is given below
<?php
class Executer {
public $path="";
public function execute($path){
// MySql connectivity
$link = mysql_connect("localhost","root","");
mysql_select_db("server_db");
//file content
$content = file_get_contents($path);
//remove the comments
$lines = explode("\n",$content);
$content = '';
foreach($lines as $line){
$line = trim($line);
if( $line && !$this->startsWith($line,'--') ){
$content .= $line . "\n";
}
}
//convert data into array of queries
$content = explode(";", $content);
//run the query
$total = $sucess=0;
foreach($content as $command){
if(trim($command)){
$success = (mysql_query($command)==false ? 0 : 1);
}
}
}
public function startsWith($string, $sym_com){
$length = strlen($sym_com);
return (substr($string, 0, $length) === $sym_com);
}
} $path = "C:/xampp/htdocs/final/downloads/server_database_file.sql";
execute($path);
I think you need to check your SQL text file encoding. because the line delimiter for each encoding is not always "\n". You can try change with "\r"
If you on localhost you can use exec function with mysqldump
exec('mysqldump server_database > C:/xampp/htdocs/final/downloads/server_database_file.sql')
Try this. Just wrote it up, realizing I didn't have a function for this. You need to verify that ; is the last character of a line, exploding by ; can lead to false mid-data splits. Below approach simply buffers the lines up until it finds a terminating ;, then inserts them into an array and resets the buffer.
function parse_sql_file($filepath) {
$queries = [];
$sql_query = [];
$lines = file($filepath);
foreach($lines as $line) {
$line = trim($line);
// This is a comment: move on, nothing to see here.
if (substr($line, 0, 2) == '--') continue;
$sql_query[] = $line;
// We found a terminator: do the needful.
if (substr($line, -1) == ';') {
$queries[] = trim( implode("\n", $sql_query) );
$sql_query = [];
}
}
return $queries;
}
$queries = parse_sql_file('my.sql');
var_dump($queries);
I have this script that extracts a .csv file from the database that holds data for different locals that a user has logged into. The .csv files come like this:
"id_user";"id_local"
"1";""
"2";"2,3,4"
"3";""
"5";"2,5"
"10";""
"13";"2"
"14";"5"
"15";"2"
"16";"1"
"20";"2"
"21";""
As you can se, it get one register per user
But, to manipulate it properly, we need it like this:
"id_user";"id_local"
"2";"2"
"2";"3
"2";"4"
"5";"2"
"5";"5"
"13";"2"
"14";"5"
"15";"2"
"16";"1"
"20";"2"
So, I need to create a function that deletes users with no local and splits different locals of the same user in different registers. Does anyone knows how can I do it?
Here is the code I have so far but I'm not sure if I'm on the right way:
function fix_local_secundario(){
$filename = "local_secundario.csv";
$file_locais = file_get_contents($filename);
$locais = explode("\n", $file_locais);
// $pattern = "/,/";
// $replacement = "\"\n;\"";
while ($line = current($locais)) {
$line = str_getcsv($line, ';', '"','\n');
// $line = preg_replace($pattern, $replacement, $line);
var_dump($line);
echo "\n";
next($locais);
}
}
Try this and see if this works:
function fix_local_secundario(){
$filename = "local_secundario.csv";
$file_locais = file_get_contents($filename);
$locais = explode("\n", $file_locais);
while ($line = current($locais)) {
// do first split on ; character
$arr1 = explode(";", $line);
// if the part after ; is not empty for this line
if ($arr1[1]!='""'){
// split it further on , character
$arr2 = explode(",", $arr1[1]);
foreach ($arr2 as $key => $val){
if($val[0] != '"'){
$val = '"'.$val;
}
if($val[strlen($val)-1] != '"'){
$val = $val . '"';
}
echo $arr1[0] . ";" . $val . "<BR>";
}
}
next($locais);
}
}
Once this basic piece is working, you should change it to return values rather than echo values since this code is part of a function as per updates made to your question.
What about this…
$f = fopen("myfile.csv", "r");
while($row = fgetcsv($f, 0, ";")){
$locals = explode(",", $row[1]);
if (count($locals)>1){
foreach($locals as $local)
// iterate with $row[0] and $local
}elseif($row[1] != "")
// use $row[0] and $row[1]
}
I've got a large flat file of usernames and emails in the following format:
"username", "email"
"username", "email"
"username", "email"
etc...
I need to take the email and search for the username, but for some reason it will not return a result. It works if I search opposite.
$string = "user_email#something.com";
$filename = "user_email.txt";
$h = fopen("$filename","r");
$flag=0;
while (!feof ($h)) {
$buffer = fgets($h);
$thisarray = split(",", $buffer);
if ($string == str_replace('"','', $thisarray[1])) {
$i = 1;
$i++;
echo '<td bgcolor="#CCFFCC"><b style="color: maroon">' . str_replace('"','',$thisarray[0]). '</b></td>';
}
Any ideas? Thanks!
As per reko_t's suggestion: Use fgetcsv to read individual lines of csv into arrays, until you find one where the second element matches your search term. The first element then is the username. Something like:
<?php
function find_user($filename, $email) {
$f = fopen($filename, "r");
$result = false;
while ($row = fgetcsv($f)) {
if ($row[1] == $email) {
$result = $row[0];
break;
}
}
fclose($f);
return $result;
}
You may use fgetcsv() directly
$string = "user_email#something.com";
$filename = "user_email.txt";
$h = fopen("$filename","r");
$flag=0;
while (!feof ($h)) {
list($username, $email= fgetcsv($h);
if ($string == $email) { /* do something */ }
}
fgetcsv() (as a nice side effect) also removes the "field enclosures" (the double quotes ") for you, if they exists.
Your own example probably does not work, because if you have such a line
"username", "email"
splitting at , will result in
'"username"'
' "email"'
Notice the whitespace before "email", that you forgot to remove. Additional using str_replace() to remove the surrounding quotes is quite unsafe. Have a look at trim().
First, just use file() to get the contents of the file into an array:
$file_contents = file( $filename, 'r' );
Now loop through the contents of the array, splitting the strings and examining the email address:
foreach ( $file_contents as $line ) {
list ( $username, $email ) = str_split( ',' $line );
if ( trim( $email ) == $string ) {
// A match was found. Take appropriate action.
}
}
I think the easiest solution is to use file() with str_getcsv().
The code would be something like this:
foreach (file($fileName, FILE_SKIP_EMPTY_LINES) as $line) {
$columns = str_getcsv($line); // Where $columns[0] and $columns[1] hold the username and email respectively.
}
I truly believe that all examples in other answers works!
But all they are slow, because all of them travers each line in csv file...
I have another example how to find desired string:
$command = sprintf("grep '%s,%s' -Er %s", $userName, $email, $file);
$result = `$command`;
Yes it some kind of dark matter, but it really works and it really fast!
While fgetcsv is potentially a more elegant solution, that doesn't answer your original question: your second array element has a newline, and you're comparing against a string that doesn't.
To fix:
if ($string == str_replace('"','', chop($thisarray[1]))) {
It seems that the delimiter of csv file edited and saved by OpenOffice Excel is ";" while microsoft office excel is ",", how should i write a program to parse the csv file no matter which delimiter it uses?
I'm using this function in one of my apps to determine which separator is used:
function get_separator( $csvstring, $fallback = ';') {
$seps = array(';',',','|',"\t");
$max = 0;
$separator = false;
foreach($seps as $sep){
$count = substr_count($csvstring, $sep);
if($count > $max){
$separator = $sep;
$max = $count;
}
}
if($separator) return $separator;
return $fallback;
}
It basically checks which separator occurs at most and returns it. It works without problems for about two years now
Use SplFileObject::getCsvControl method.
Example usage:
<?php
$csvFileObject = new SplFileObject($_FILES["csv"]["tmp_name"]);
list($delimiter, $enclosure) = $csvFileObject->getCsvControl();
$lines = fopen($_FILES["csv"]["tmp_name"], 'r');
if($lines) {
while (($line = fgetcsv($lines, 4096, $delimiter, $enclosure)) !== false) {
//do something
}
}
Reference: http://php.net/manual/en/splfileobject.getcsvcontrol.php
fgetcsv() allows you to specify the delimiter as the third argument.
As for automatically detecting, there are some interesting answers for this question.