Search And Replace Existing Array Element Within File - PHP - php

$static = ');';
$file = 'onebigarray.php';
$fh = fopen($file, 'r+');
include $file;
if (in_array($keyname, $udatarray)) {
$key = array_search($keyname, $udatarray);
$fsearch = $key + 4;
fseek($fh, $fsearch, SEEK_END);
fwrite($fh, 'new data');
fseek($fh, - 2, SEEK_END);
fwrite($fh, $static);
fclose($fh);
}
I'm a novice at PHP.
What I've done is created a form that writes array elements to a file "onebigarray.php".
The file looks like
Array (
'name',
'data',
'name2',
'data2',
);
What I ultimately need to do, is load that $file, search the array for an existing name then replace 'data(2)' with whatever was put in the form. The entire script is extremely large and consists of 3 different files, it works but now I need to find a way to search and replace array elements within an existing file, and then write them to that file. This section of the script is where that's going to need to occur and it's the part that's giving me the most trouble, currently it seems to properly load and enact the if/else statement, however completely ignores fwrite (I can only assume there's an issue with including and opening the same file within the same script).
Thank you in advance for any help.

Your code can be simplified greatly, but with some notable design changes. Firstly, your stored array structure is not efficient and negates the benefit of using an array in the first place. A very powerful feature of arrays is their ability to store data with a meaningful key (known as an associative array). In this case your array should look like this:
array(
'name' => 'data',
'name2' => 'data2'
);
This allows you to retrieve the data directly by the key name, e.g. $data = $array['name2'].
Secondly, changing the data stored in 'onebigarray.php' from PHP code to JSON makes it trivial for any other system to interact and makes it easier to extend later.
Assuming that the file is renamed to 'onebigarray.json' and its content looks like this (after using json_encode() on the array above):
{"name":"data","name2":"data2"}
Then the below code will work nicely:
<?php
$file = 'onebigarray.json';
$key = 'name2';
$new_data = 'CHANGED';
$a = (array) json_decode(file_get_contents($file));
if (array_key_exists($key, $a)) {
$a[$key] = $new_data;
file_put_contents($file, json_encode($a));
}
?>
After running the above, the JSON file will now contain this:
{"name":"data","name2":"CHANGED"}
A big caveat: this will read the entire JSON file into memory! So depending on how big the file really is this may negatively impact server performance (although it would probably need to be several megabytes before the server even noticed, and even then with a trivial impact on performance).

Related

Is it possible to load a single row from a CSV file?

Using PHP, is it possible to load just a single record / row from a CSV file?
In other words, I would like to treat the file as an array, but don't want to load the entire file into memory.
I know this is really what a database is for, but I am just looking for a down and dirty solution to use during development.
Edit: To clarify, I know exactly which row contains the info I am looking for.
I would just like to know if there is a way to get it without having to read the entire file into memory.
As I understand you are looking for a row with certain data. Therefore you could probably implement the following logic:
(1) scan file for the given data (ex. value which is in the row that you are trying to find),
(2) load only this line of file,
(3) perform your operations on that line.
fgetcsv() operates over a file resource handle, so if you want you can obtain the position of the line you can fseek() the resource to that position and use fgetcsv() normally.
If you don't know which line you are looking for until after you have read the row, your best bet is reading the record until you find the record by testing the array that is returned.
$fp = fopen('data.csv', 'r');
while(false !== ($data = fgetcsv($fp, 0, ','))) {
if ($data['field'] === 'somevalue') {
echo 'Hurray';
break;
}
}
If you are looking to read a specific line, use the splfile object and seek to the record number. This will return a string that you must convert to an array
$file = new SplFileObject('data.csv');
$file->seek(2);
$record = $file->current();
$data = explode(",", $record);

Reading csv file with large number of fields

I have csv file with 104 fields, but I need only 4 fields to use in mysql database. each file has about a million rows.
could somebody tell me efficient way to do this? reading each line to array takes long time.
thanks
You have to read every line in its entirety by definition. This is necessary to find the delimiter for the next record (i.e. the newline character). You only need to discard the data you have read that you don't need. E.g.:
$data = array();
$fh = fopen('data.csv', 'r');
$headers = fgetcsv($fh);
while ($row = fgetcsv($fh)) {
$row = array_combine($headers, $row);
$data[] = array_intersect_key($row, array_flip(array('foo', 'bar', 'baz')));
// alternatively, if you know the column index, something like:
// $data[] = array($row[1], $row[45], $row[60]);
}
This only retains the columns foo, bar and baz and discards the rest. The reading from file (fgetcsv) is about as fast as it gets. If you need it any faster, you'll have to implement your own CSV tokenizer and parser which skips over the columns you don't need without even temporarily storing them in memory; how much of a performance boost this brings vs. development time necessary to implement this bug free is very debatable.
simple excel macro can drop all unnecessary columns (100 out of 104)
within second. I am looking for similar solution.
That is because Excel, once a file is opened, has all data in memory and can act on it very quickly. For an accurate comparison you need to compare the time it takes to open the file in Excel + dropping of the columns, not just dropping the columns.

PHP - read from flatfile, remove line and write back to flat file

Would appreciate some assistance
i have a txt file witht he following contents:
1234|dog|apartment|two
1234|cat|apartment|one
1234|dog|house|two
1234|dog|apartment|three
I want to delete the entry where the animal is "dog" living in an "house"
<?php
if (isset($_POST['delete_entry]))
{
//identifies the file
$file = "db.txt";
//opens the file to read
#$fpo = fopen($file, 'r');
//while we have not reached the end of the file
while(!feof($fpo))
{
//read each line of the file into an array called animal
$animal[] = fgets($fpo);
}
//close the file
fclose($fpo);
//iterate through the array
foreach ($animal as $a)
{
if the string contains dog and apartment
if ((stripos ($a, 'dog']))&&(stripos ($a, 'house')))
{
//dont do anything
}
else
{
//otherwise print out the string
echo $a.'<br/>';
}
}
}
?>
This successfully prints out the array without the entry where 'dog' and 'house' appears.
I need to write this back to the flat file though, but running into difficulties.
I have tried a variety of options include writting back to the file immediately when each entry is found.
Warning: feof() expects parameter 1 to be resource, boolean given in
Warning: fwrite(): 9 is not a valid stream resource in
Warning: fclose(): 9 is not a valid stream resource in
These are amongst the errors i have encountered. Now from my understanding of arrays,
- when i go through this array called animal,
- it checks index [0] for the two conditions and
- if the entry is not found, it assigns to to $a.
- It then goes through the array starting at index [1],
- and so forth.
Each time the new value is assigned to $a.
I thought that printing it to file each time it appears might work, but this is where i get the fwrite and fclose errors above, and no idea how to resolve this (yet).
I still have to do the bit where i need to replace 'apartment' with house, for one specifically selected entry, but will get there once I have sorted out the "delete"
I dont need code, maybe just a logic flow that might assist me.
Thanks
To save some time, you could store your data in array only if it passes your validation rules when it's being read from file, and after reading the end of file, you'd have array ready for writing it back to file.
How about this for steps:
Read the file.
Store File contents in array.
Remove item from array.
Overwrite the file with new contents.
What you can do is opening the source file in read mode and a temporary file in write mode. As you read content from the "in" file, you write lines to the "out" file. When the "in" file is processed and closed, you rename "out" to "in". This way you need to worry less about memory constraints.
When processing each line, it's better if you split on '|', so you know that the second element contains an animal name and the third element contains a housing name. Who knows if a cat is living in a doghouse.
<?php
$fileName = 'db.txt';
$data = #file($fileName);
$id = 0;
$animal = "";
$type = "";
$number = 0;
$excludeAnimal = array("dog");
$excludeHouseType = array("house");
foreach($data as $row) {
list($id,$animal,$type,$number) = explode("|",$row);
if(in_array($animal,$excludeAnimal) && in_array($type,$excludeHouseType))
continue
/* ... code ... */
}
?>
Although this doesn't answer your original question, I'd like to share what I've come up with.
I'm pretty sure this will do your entire script in three lines:
$file = file_get_contents( 'db.txt');
$result = preg_replace('/^\d+\|dog\|house\|\w+$/m', '', $file);
file_put_contents( 'db.txt', $result);
It uses a regex to replace the lines with dog|house, then writes the file back.
Read and dump all data until the one you want deleted into $array_1.
Read and dump rest of file into $array_2.
Concatenate 2 arrays in a $newarray, rewrite to original flatfile.
Simple!

Which method is better? Hashing each line in a file with PHP

This question was asked on a message board, and I want to get a definitive answer and intelligent debate about which method is more semantically correct and less resource intensive.
Say I have a file with each line in that file containing a string. I want to generate an MD5 hash for each line and write it to the same file, overwriting the previous data. My first thought was to do this:
$file = 'strings.txt';
$lines = file($file);
$handle = fopen($file, 'w+');
foreach ($lines as $line)
{
fwrite($handle, md5(trim($line))."\n");
}
fclose($handle);
Another user pointed out that file_get_contents() and file_put_contents() were better than using fwrite() in a loop. Their solution:
$thefile = 'strings.txt';
$newfile = 'newstrings.txt';
$current = file_get_contents($thefile);
$explodedcurrent = explode('\n', $thefile);
$temp = '';
foreach ($explodedcurrent as $string)
$temp .= md5(trim($string)) . '\n';
$newfile = file_put_contents($newfile, $temp);
My argument is that since the main goal of this is to get the file into an array, and file_get_contents() is the preferred way to read the contents of a file into a string, file() is more appropriate and allows us to cut out another unnecessary function, explode().
Furthermore, by directly manipulating the file using fopen(), fwrite(), and fclose() (which is the exact same as one call to file_put_contents()) there is no need to have extraneous variables in which to store the converted strings; you're writing them directly to the file.
My method is the exact same as the alternative - the same number of opens/closes on the file - except mine is shorter and more semantically correct.
What do you have to say, and which one would you choose?
This should be more efficient and less resource-intensive as the previous two methods:
$file = 'passwords.txt';
$passwords = file($file);
$converted = fopen($file, 'w+');
while (count($passwords) > 0)
{
static $i = 0;
fwrite($converted, md5(trim($passwords[$i])));
unset($passwords[$i]);
$i++;
}
fclose($converted);
echo 'Done.';
As one of the comments suggests do what makes more sense to you. Since you might come back to this code in few months and you need to spend least amount of time trying to understand it.
However, if speed is your concern then I would create two test cases (you pretty much already got them) and use timestamp (create variable with timestamp at the beginning of the script, then at the end of the script subtract it from timestamp at the end of the script to work out the difference - how long it took to run the script.) Prepare few files I would go for about 3, two extremes and one normal file. To see which version runs faster.
http://php.net/manual/en/function.time.php
I would think that differences would be marginal, but it also depends on your file sizes.
I'd propose to write a new temporary file, while you process the input one. Once done, overwrite the input file with the temporary one.

PHP: Writing and sorting a file

I'm trying to write a php function that takes the $name and $time and write it to a txt file (no mySQL) and sort the file numerically.
For example:
10.2342 bob
11.3848 CandyBoy
11.3859 Minsi
12.2001 dj
just added Minsi under a faster time, for example.
If the $name already exists in the file, only rewrite it if the time is faster (smaller) than the previous one, and only write if the time fits within 300 entries to keep the file small.
My forte isn't file writing but I was guessing to go about using the file() to turn the whole file into an array, but to my avail, it didn't work quite like I wanted. Any help would be appreciated
If your data sets are small, you may consider using var_export()
function dump($filename, Array &$data){
return file_put_contents('<?php return ' . var_export($data, true) . ';');
}
// create a data set
$myData = array('alpha', 'beta', 'gamma');
// save a data set
dump('file.dat', $myData);
// load a data set
$myData = require('file.dat');
Perform your sorts using the PHP array_* functions, and dump when necessary. var_export() saves the data as PHP parsable text, which is why the dump() function prepends the string <?php return. Of course, this is really only a viable option when your data sets are going to be small enough that keeping their contents in memory is not unreasonable.
Try creating a multi dimensional array "$timeArray[key][time] = name" and then sort($timeArray)

Categories