I need to compare two CSV file that both contain two columns: ID and URL and check if the URL are differents. The two file normally, are the same but sometimes it can change. So i have to compare if the ID is the same and if the URL has change. I would like do this with a multidimensional loop (both of files are very big). But i don't understand why at the first match, the loop is stopped.
I try to do this with a while loop:
while ($file_odierno_fr = fgetcsv($product_dinamica_fr, 0, ";", '"')) {
while ($file_precedente_fr = fgetcsv($product_dinamica_fr_pre, 0, ";", '"' )) {
// the index [1] is the URL and ID is the index [0]
if ($file_odierno_fr[1] !== $file_precedente_fr[1] && $file_odierno_fr[0] == $file_precedente_fr[0]){
$textMail .= "\n\nURL file odierno: <b>".$file_odierno_fr[1]. "</b>\nURL file pecedente: <b>". $file_precedente_fr[1] . "</b>\n\n";
fputcsv($file,array($file_odierno_fr[1], $file_precedente_fr[1]),";");
$sendMail = TRUE;
}
}
}
fclose($product_dinamica_fr);
fclose($product_dinamica_fr_pre);
But when igo to debug this, i get juste the first match and the rest is ignored. I change some URL in the file for be sure that all is working.
I think that i can't do while loop like this, but i'm not sure. There is a way for do that with while loop?
Please try to following code and give a feedback:
$separator = ";";
$enclosure = '"';
$lineSize = 0;// 0 := unlimited
$textMail = "";
while($lineNow = fgetcsv($product_dinamica_fr, $lineSize, $separator, $enclosure))
{
while($linePre = fgetcsv($product_dinamica_fr_pre, $lineSize, $separator, $enclosure))
{
$idNow = trim($lineNow[0]);
$idPre = trim($linePre[0]);
$urlNow = trim($lineNow[1]);
$urlPre = trim($linePre[1]);
// Compare IDs first. If they are not the same, then skip this line
if($idNow != $idPre)
continue;
// If URLs are the same then skip this line
if( $urlNow == $urlPre)
{
continue;
}
// Set email flag and add info to e-mail content
$sendMail = TRUE;
$textMail .= "\n\nURL file odierno: <b>$urlNow</b>\nURL file pecedente: <b>$urlPre</b>\n\n";
// Write the difference to local file
fputcsv($file, [$urlNow, $urlPre], ";");
}
rewind($product_dinamica_fr_pre);
}
fclose($product_dinamica_fr);
fclose($product_dinamica_fr_pre);
echo $textMail;
Related
I wrote query in php file ,my query is:
$query = "SELECT cc.NAME complex_check_name,f.name server_name,
sgk.NAME single_check_name,cc.operator
FROM complex_check cc,
lnksinglechecktocomplexcheck lk,
single_checks sgk,
functionalci f ,
lnkconfigurationitemtosinglecheck lkcg
WHERE cc.id = lk.complex_check_id AND
sgk.id = lk.single_check_id and
sgk.id = lkcg.single_check_id AND
lkcg.config_item_id = f.id ";
if ($result=mysqli_query($link,$query))
{
while ($obj=mysqli_fetch_object($result))
{
$list= $obj->complex_check_name .
"#".
$obj->server_name .
";".
$obj->single_check_name .
$obj-> operator;
echo $list .'<br>';
}
}
The result is :
test_com_check_sep01#INFRASEP01;cpu check sep01&
test_com_check_sep01#INFRASEP01;DB check sep01&
test_com_check_sep01#INFRASEP01;disk space check sep01&
test_com_check_sep02#INFRASEP02;cpu check sep02||
test_com_check_sep02#INFRASEP02;db check sep02||
test_com_check_sep02#INFRASEP02;disk space check sep02||
How can I concatenate the string as:
"test_com_check_sep01=INFRASEP01;cpu check sep01&INFRASEP01;DBcheck sep01&INFRASEP01;disk space check sep01"
"test_com_check_sep02=INFRASEP02;cpu check sep02||INFRASEP02;db check sep02||INFRASEP02;disk space check sep02"
You could store the values into an array and implode afterwards.
$check = array();
if($result = mysqli_query($link,$query)) {
while($obj = mysqli_fetch_object($result)) {
// If value is not stored in check array proceed
if(!in_array($obj->complex_check_name,$check))
$list[$obj->complex_check_name][] = $obj->complex_check_name."=";
$list[$obj->complex_check_name][] = $obj->server_name.";".$obj->single_check_name.$obj->operator;
// Store in check array
$check[] = $obj->complex_check_name;
}
// Loop through stored rows and implode with break
foreach($list as $array) {
echo implode("<br />",$array);
}
}
try this
$concat1 = '';
$concat2 = '';
if ($result=mysqli_query($link,$query))
{
while ($obj=mysqli_fetch_object($result))
{
if($obj->server_name == 'INFRASEP01'){
concat1 .= $obj->complex_check_name . "#".$obj->server_name .";". $obj->single_check_name . $obj-> operator;
}else{
concat2 .= $obj->complex_check_name . "#".$obj->server_name .";". $obj->single_check_name . $obj-> operator;
}
}
}
echo $concat1 .'<br>'.$concat2;
Assuming you want to keep the lines separate for use, you could do this
$list = array("INFRASEP01", "INFRASEP01", "INFRASEP02");
$concatINFRASEP01 = "";
$concatINFRASEP02 = "";
for($lineCounter = 0; $lineCounter < sizeof($list); $lineCounter++)
if(strpos($list[$lineCounter], "INFRASEP01") !== false){
//Found it
$concatINFRASEP01 .= " " . $list[$lineCounter];
}
else if(strpos($list[$lineCounter], "INFRASEP02") !== false){
$concatINFRASEP02 .= " " . $list[$lineCounter];
}
NOTE: I did not test this code so there may be errors.
If you do not need the $list array, then you can do as #Malakiof suggested.
EDIT (01/22/2015): I have improved my answer but left the old one there in case I misunderstood.
//In your case the rows come from the $obj (which most would call $row)
$listOfRows = array("test_com_check_sep01#INFRASEP01;cpu check sep01&","test_com_check_sep01#INFRASEP01;DB check sep01&", "test_com_check_sep02#INFRASEP02;cpu check sep02||");
//Create this array as you go through each row by adding the server_name
//to this array. You can skip making this array and simply make the
//unique array by checking if the array contains the server_name.
$listServerNames = array("INFRASEP01","INFRASEP02","INFRASEP01", "INFRASEP02", "INFRASEP01");
//Only have unique server names to avoid duplicates
$listUniqueServerNames = array_unique($listServerNames);
//this will be your list of concatenated strings
$concatByServerName = array();
//Go through the unique server names one by one
foreach($listUniqueServerNames as $serverName)
//While looking at each unique server name, look through the rows
foreach($listOfRows as $line)
if(strpos($line, $serverName) !== false){
//Found it
if(array_key_exists($serverName, $concatByServerName))
$concatByServerName[$serverName] .= " " . $line;
else
$concatByServerName[$serverName] = $line;
}
If the $listOfRows is very large, consider making a copy of $listOfRows and removing the lines from $listOfRows when you add them to $concatByServerName.
Although this is not the best way to do it, I am trying to keep it simple in order for you to be able to get it to work, while fully understanding what is happening. You can easily improve on this code by looking at your project and streamlining these tasks.
So this is my very simple and basic account system (Just a school project), I would like the users to be able to change their password. But I am unsure on how to just replace the Password value within a row keeping all the other values the same.
CSV File:
ID,Username,Email,DateJoined,Password,UserScore,profilePics
1,Test,Test#Test.com,03/12/2014,Test,10,uploads/profilePics/Test.jpg
2,Alfie,Alfie#test.com,05/12/2014,1234,136,uploads/profilePics/Alfie.png
PHP:
("cNewPassword" = confirm new password)
<?php
session_start();
if(empty($_POST['oldPassword']) || empty($_POST['newPassword']) || empty($_POST['cNewPassword'])) {
die("ERROR|Please fill out all of the fields.");
} else {
if($_POST['newPassword'] == $_POST['cNewPassword']) {
if ($_POST['oldPassword'] == $_SESSION['password']) {
$file = "Database/Users.csv";
$fh = fopen($file, "w");
while(! feof($file)) {
$rows = fgetcsv($file);
if ($rows[4] == $_POST['oldPassword'] && $rows[1] == $_SESSION['username']) {
//Replace line here
echo("SUCCESS|Password changed!");
}
}
fclose($file);
}
die("ERROR|Your current password is not correct!");
}
die("ERROR|New passwords do not match!");
}
?>
You'll have to open file in read mode, open a temporary one in write mode, write there modified data, and then delete/rename files. I'd suggest trying to set up a real DB and work using it but if you're going for the csv, the code should look like more or less like this:
$input = fopen('Database/Users.csv', 'r'); //open for reading
$output = fopen('Database/temporary.csv', 'w'); //open for writing
while( false !== ( $data = fgetcsv($input) ) ){ //read each line as an array
//modify data here
if ($data[4] == $_POST['oldPassword'] && $data[1] == $_SESSION['username']) {
//Replace line here
$data[4] = $_POST['newPassword'];
echo("SUCCESS|Password changed!");
}
//write modified data to new file
fputcsv( $output, $data);
}
//close both files
fclose( $input );
fclose( $output );
//clean up
unlink('Database/Users.csv');// Delete obsolete BD
rename('Database/temporary.csv', 'Database/Users.csv'); //Rename temporary to new
Hope it helps.
My suggestion is a little function of mine which will turn your database data into an array which you can modify and then return to original state:
With this set of function, you simply have to precise how each row/row data are separated.
function dbToArray($db, $row_separator = "\n", $data_separator = ",") {
// Let's seperator each row of data.
$separate = explode($row_separator, $db);
// First line is always the table column name:
$table_columns =
$table_rows = array();
foreach ($separate as $key => $row) {
// Now let's get each column data out.
$data = explode($data_separator, $row);
// I always assume the first $row of data contains the column names.
if ($key == 0)
$table_columns = $data;
else if ($key > 0 && count($table_columns) == count($data)) // Let's just make sure column amount matches.
$table_rows[] = array_combine($table_columns, $data);
}
// Return an array with columns, and rows; each row data is bound with it's equivalent column name.
return array(
'columns' => $table_columns,
'rows' => $table_rows,
);
}
function arrayToDb(array $db, $row_separator = "\n", $data_separator = ",") {
// A valid db array must contain a columns and rows keys.
if (isset($db['columns']) && isset($db['rows'])) {
// Let's now make sure it contains an array. (This might too exagerated of me to check that)
$db['columns'] = (array) $db['columns'];
$db['rows'] = (array) $db['rows'];
// Now let's rewrite the db string imploding columns:
$returnDB = implode($data_separator, $db['columns']).$row_separator;
foreach ($db['rows'] as $row) {
// And imploding each row data.
$returnDB .= implode($data_separator, $row).$row_separator;
}
// Retunr the data.
return $returnDB;
}
// Faaaaaaaaaaaail !
return FALSE;
}
Let's just point out I tried these with your db example, and it works even when tested on it's own results such as : dbToArray(arrayToDb(dbToArray())) multiple times.
Hope that help. If I can be clearer don't hesitate. :)
Cheers,
You need a 3 step process to do this (create 3 loops, could be optimized to 1 or 2 loops):
Load the relevant data to memory
Update the desired data
Save the data to the file
Good luck! :)
PS. Also your passwords should never been stored in clear text, wether in memory(session) or on disk(csv), use a hasing function!
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 want to record downloads in a text file
Someone comes to my site and downloads something, it will add a new row to the text file if it hasn't already or increment the current one.
I have tried
$filename = 'a.txt';
$lines = file($filename);
$linea = array();
foreach ($lines as $line)
{
$linea[] = explode("|",$line);
}
$linea[0][1] ++;
$a = $linea[0][0] . "|" . $linea[0][1];
file_put_contents($filename, $a);
but it always increments it by more than 1
The text file format is
name|download_count
You're doing your incrementing outside of the for loop, and only accessing the [0]th element so nothing is changing anywhere else.
This should probably look something like:
$filename = 'a.txt';
$lines = file($filename);
// $k = key, $v = value
foreach ($lines as $k=>$v) {
$exploded = explode("|", $v);
// Does this match the site name you're trying to increment?
if ($exploded[0] == "some_name_up_to_you") {
$exploded[1]++;
// To make changes to the source array,
// it must be referenced using the key.
// (If you just change $v, the source won't be updated.)
$lines[$k] = implode("|", $exploded);
}
}
// Write.
file_put_contents($filename, $lines);
You should probably be using a database for this, though. Check out PDO and MYSQL and you'll be on your way to awesomeness.
EDIT
To do what you mentioned in your comments, you can set a boolean flag, and trigger it as you walk through the array. This may warrant a break, too, if you're only looking for one thing:
...
$found = false;
foreach ($lines as $k=>$v) {
$exploded = explode("|", $v);
if ($exploded[0] == "some_name_up_to_you") {
$found = true;
$exploded[1]++;
$lines[$k] = implode("|", $exploded);
break; // ???
}
}
if (!$found) {
$lines[] = "THE_NEW_SITE|1";
}
...
one hand you are using a foreach loop, another hand you are write only the first line into your file after storing it in $a... it's making me confuse what do you have in your .txt file...
Try this below code... hope it will solve your problem...
$filename = 'a.txt';
// get file contents and split it...
$data = explode('|',file_get_contents($filename));
// increment the counting number...
$data[1]++;
// join the contents...
$data = implode('|',$data);
file_put_contents($filename, $data);
Instead of creating your own structure inside a text file, why not just use PHP arrays to keep track? You should also apply proper locking to prevent race conditions:
function recordDownload($download, $counter = 'default')
{
// open lock file and acquire exclusive lock
if (false === ($f = fopen("$counter.lock", "c"))) {
return;
}
flock($f, LOCK_EX);
// read counter data
if (file_exists("$counter.stats")) {
$stats = include "$counter.stats";
} else {
$stats = array();
}
if (isset($stats[$download])) {
$stats[$download]++;
} else {
$stats[$download] = 1;
}
// write back counter data
file_put_contents('counter.txt', '<?php return ' . var_export($stats, true) . '?>');
// release exclusive lock
fclose($f);
}
recordDownload('product1'); // will save in default.stats
recordDownload('product2', 'special'); // will save in special.stats
personally i suggest using a json blob as the content of the text file. then you can read the file into php, decode it (json_decode), manipulate the data, then resave it.
$file = fopen("test.txt","r");
while($line = fgets($file)) {
$line = trim($line);
list($model,$price) = preg_split('/\s+/',$line);
if(empty($price)) {
$price = 0;
}
$sql = "UPDATE products
SET products_price=$price
WHERE products_model='$model'";
// run the sql query.
}
fclose($file);
the txt file like this:
model price
LB2117 19.49
LB2381 25.99
1, what's the meaning of list($model,$price) = preg_split('/\s+/',$line);
i know preg_split like explode, but i don't know what't the parameter meaning of the above line
2, how to skip the first record.
it's taking the results of the preg_split and assigning them to the vars $model and $price. You're looking at a parsing algorithm. Sorry if this is not enough. I have a hard time understanding the question as it is written.
Also, if I read this correctly, there is no need to skip line 1 unless you have an item with the model defined as "model" in the database.
But if you wanted to for some reason, you could add a counter...
$i = 0;
while($line = fgets($file)) {
if($i > 0)
{
$line = trim($line);
list($model,$price) = preg_split('/\s+/',$line);
if(empty($price)) {
$price = 0;
}
$sql = "UPDATE products
SET products_price=$price
WHERE products_model='$model'";
// run the sql query.
}
$i++;
}
That is a language construct that allows you to assign to multiple variables at once. You can think of it as array unpacking (preg_split returns an array). So, when you do:
<?php
list($a, $b) = explode(".","a.b");
echo $a . "\n";
echo $b . "\n";
You will get:
a
b
Having less elements in list than the array is ok, excess elements in array are ignored, but having insufficent elements in array will give you an undefined index error. For example:
list($a) = explode(".","a.b"); // ok
list($a,$b,$c) = explode(".","a.b") // error
I don't know if you meant that by skip the first record but...
$file = fopen("test.txt","r"); // open file for reading
$first = true;
while($line = fgets($file)) { // get the content file
if ($first === true) { $first = false;}//skip the first record
else{
$line = trim($line); // remove the whitespace before and after the test
// not in the middle
list($model,$price) = preg_split('/\s+/',$line); // create two variable model and price, the values are from the preg_split \s means whitespace, tab and linebreak
if(empty($price)) { // if $price is empty price =0
$price = 0;
}
$sql = "UPDATE products // sql update
SET products_price=$price
WHERE products_model='$model'";
// run the sql query.
}
}
fclose($file); //close the file