I have a simple txt file with email addresses. I want to check if these addresses are in my database and if so: delete them.
The txt file is not in a csv format, but every email addresses is on a new line. I'm wondering whats the best way to do this.
Steps:
This regular expression will match a new line
([^\n]*\n+)+
Add a comma after every line (or replace the NEWLINE with comma) so the list will become from
email1#com.com
email2#com.com
email3#com.com
to email#com.com,email2#com.com,email3#com.com
Add brackets to the beggining and end:
(email#com.com,email2#com.com,email3#com.com)
Add the following sql:
DELETE FROM database.schema.table WHERE email_address IN (email#com.com,email2#com.com,email3#com.com);
Execute the SQL.
You can execute the query from php or directly in the database, keep backups please else you might screw up smth...
Hope this helps...
Good Luck
The function you're looking for is fgets().
<?php
$emails = array();
if( ! $fh = fopen('file.txt', 'r') ) { die('could not open file'); }
while( $buffer = fgets($fh, 4096) ) {
$emails[] = $buffer;
}
fclose($fh);
foreach($emails as $email) {
$query = sprintf("DELETE FROM table WHERE email LIKE '%s'", $email);
// do the query
}
<?php
$file = file("emails.txt");
foreach ($file as $email) {
$query = sprintf("DELETE FROM table WHERE email LIKE '%s'", $email);
# execute query
}
?>
Read the emails in one at a time and then run the delete query with the value. DO NOT USE mysql_query (unless you trust the input from text file, but even then just use the newer libraries please). If the records are there, they will be deleted, if not no biggie nothing happens. Done.
Related
I have I have static HTML / JS page without any database (I don't need it). However I start fight with some issue. I need to generate random ID which have to be unique(used once and never ever again).
Stardard MySQL way:
On standard application I will do it with storing all used IDs in database
and when needed new one I will simply
// I generate ID here, let's say it's 123
SELECT COUNT(id) FROM table WHERE id = 123
My solution which may be not the best one:
I am thinking alternative may be some storing in file
// Let's generate ID here, and make it 123 again
$handle = fopen("listOfIDs.txt", "r");
if ($handle) {
$used = false;
while (($line = fgets($handle)) !== false) {
if($line = 123) {
$used = true;
break;
}
}
fclose($handle);
return $used;
} else {
// error opening the file.
}
Dispite the fact I can imagine my option may work it could be super slow when file become bigger.
Question:
What's the best way to keep simple unique IDs without using database.
Edit:
I forgot to mentioned that unique ID have to be numbers only.
You could use uniqid(), str_rand(something), timestamp, some hash with random data that you probably never get twice.
Or, doing your way, you could have a single line with information in this file, just the last used id:
$fp = fopen("lastID.txt", "r+");
if (flock($fp, LOCK_EX)) { // lock the file
$lastId = fgets($fp); // get last id
$newId = $lastId +1; //update the id
ftruncate($fp, 0); // truncate file
fwrite($fp, $newId); //write the new Id
fflush($fp); // flush output
flock($fp, LOCK_UN); // release the lock
} else {
throw new Exception("Could not get the lock");
}
fclose($fp);
return $newId;
Maybe you can use a mix of the current timestamp, the request ip, and a randomnumber:
$unique = microtime().$_SERVER['REMOTE_HOST'].rand(0,9999);
Sure theorically you can get a request that executes this operation in the same microtime, with the same remote host, and matching the random number, but it's almost impossible, I think.
You can use PHP uniqid with $more_entropy = true, which increases the likelihood that the result will be unique.
$id = uniqid("", true);
You can also work some random number out using current date and time, etc. You should consider how fast the users may generate these numbers, if it's super fast, there might be a possibility of two different users generating the same $id because it happened at the same time.
I have this function, and this deletes textfiles after a certain age from my database automatically.
$r = new textfiles;
$db = new DB;
$currTime_ori = $db->queryOneRow("SELECT NOW() as now");
...
if($this->site->textfilesretentiondays != 0)
{
echo "PostPrc : Deleting textfiles older than ".$this->site->textfilesretentiondays." days\n";
$result = $db->query(sprintf("select ID from textfiles where postdate < %s - interval %d day", $db->escapeString($currTime_ori["now"]), $this->site->textfilesretentiondays));
foreach ($result as $row)
$r->delete($row["ID"]);
}
Now I would edit this function so that at first all textfiles are automatically downloaded in a root directory /www/backup and then the script should delete the textfiles with the string $r->delete($row["ID"]);
At the moment I have no idea how I could implement this.
For me it's seems to be impossible to give you an completely answer to your question because leak of informations.
Do you store the whole file-content in database or only the path and filename?
It would help us to see whats the content of "$row" which represents one row from database.
If you just store the filename (and optionally the path) you could use the "copy" (http://php.net/manual/de/function.copy.php) function from php to copy the file to your backup-directory. Please note, you have to ensure that the user who's executing the script or running the web-server have the privileges to write into the directory.
You could add this functionality to class textfiles as as method like makeBackup.
There are few information, but I'll give it a try. If you want to backup the rows before deleting them, you can store them in .txt file in json_encoded form using this piece of code inserted in the FOREACH loop, before delete command:
$myfile = fopen("/www/backup/".$row["ID"].".txt", "w") or die("Unable to open file!");
$txt = json_encode($row);
fwrite($myfile, $txt);
fclose($myfile);
By your approach ..
function delete ($id){
$result = $db->query(sprintf("select * from textfiles where id=$id);
//if you have filepath use copy as SebTM suggested
$path = $row['path']; //assuming path is the column name in ur db
$filename = basename($path); //to get filename
$backup_location = '/www/backup/'.$filename;
copy($path, $backup_location);
//if you have data in db
$content = $row['data'] //assuming data to be backed up to file is in a field 'data'
$backup_location = '/www/backup/file.txt';
file_put_contents($backup_location, $content);
}
But this is not the most optimal approach , you could shift even the initial query into delete function above , and call delete function only once, instead of calling it in a loop ..
I need to run some SQL scripts to my database, to update the schema and data (some kind of migration).
Because there is some logic to check before running each script, I'm writting a small PHP tool to execute the scripts, but I have a simple problem: Can I load and execute a "simple" SQL script (including table manipulation, triggers & stored procedures updates) directly, or should I add markers to the script (to mark where each sentence ends), and run the script sentence by sentence?
For the database access I'm using the PDO.
I had a similar situation today.
My solution is extremely simple, but is just smart enough to allow for comments and statements that span multiple lines.
// open script file
$scriptfile = fopen($script_path, "r");
if (!$scriptfile) { die("ERROR: Couldn't open {$scriptfile}.\n"); }
// grab each line of file, skipping comments and blank lines
$script = '';
while (($line = fgets($scriptfile)) !== false) {
$line = trim($line);
if(preg_match("/^#|^--|^$/", $line)){ continue; }
$script .= $line;
}
// explode script by semicolon and run each statement
$statements = explode(';', $script);
foreach($statements as $sql){
if($sql === '') { continue; }
$query = $pdo->prepare($sql);
$query->execute();
if($query->errorCode() !== '00000'){ die("ERROR: SQL error code: ".$query->errorCode()."\n"); }
}
Automatically build mySql table upon a CSV file upload.
I have a admin section where admin can upload CSV files with different column count and different column name.
which it should then build a mySql table in the db which will read the first line and create the columns and then import the data accordingly.
I am aware of a similar issue, but this is different because of the following specs.
The name of the Table should be the name of the file (minus the extension [.csv])
each csv file can be diffrent
Should build a table with number of columns and names from the CSV file
add the the data from the second line and on
Here is a design sketch
Maybe there are known frameworks that makes this easy.
Thanks.
$file = 'filename.csv';
$table = 'table_name';
// get structure from csv and insert db
ini_set('auto_detect_line_endings',TRUE);
$handle = fopen($file,'r');
// first row, structure
if ( ($data = fgetcsv($handle) ) === FALSE ) {
echo "Cannot read from csv $file";die();
}
$fields = array();
$field_count = 0;
for($i=0;$i<count($data); $i++) {
$f = strtolower(trim($data[$i]));
if ($f) {
// normalize the field name, strip to 20 chars if too long
$f = substr(preg_replace ('/[^0-9a-z]/', '_', $f), 0, 20);
$field_count++;
$fields[] = $f.' VARCHAR(50)';
}
}
$sql = "CREATE TABLE $table (" . implode(', ', $fields) . ')';
echo $sql . "<br /><br />";
// $db->query($sql);
while ( ($data = fgetcsv($handle) ) !== FALSE ) {
$fields = array();
for($i=0;$i<$field_count; $i++) {
$fields[] = '\''.addslashes($data[$i]).'\'';
}
$sql = "Insert into $table values(" . implode(', ', $fields) . ')';
echo $sql;
// $db->query($sql);
}
fclose($handle);
ini_set('auto_detect_line_endings',FALSE);
Maybe this function will help you.
fgetcsv
(PHP 4, PHP 5)
fgetcsv — Gets line from file pointer
and parse for CSV fields
http://php.net/manual/en/function.fgetcsv.php
http://bytes.com/topic/mysql/answers/746696-create-mysql-table-field-headings-line-csv-file has a good example of how to do this.
The second example should put you on the right track, there isn't some automatic way to do it so your going to need to do a lil programming but it shouldn't be too hard once you implement that code as a starting point.
Building a table is a query like any other and theoretically you could get the names of your columns from the first row of a csv file.
However, there are some practical problems:
How would you know what data type a certain column is?
How would you know what the indexes are?
How would you get data out of the table / how would you know what column represents what?
As you can´t relate your new table to anything else, you are kind of defeating the purpose of a relational database so you might as well just keep and use the csv file.
What you are describing sounds like an ETL tool. Perhaps Google for MySQL ETL tools...You are going to have to decide what OS and style you want.
Or just write your own...
I have this code (which thanks to the users of stackoverflow I got the markup I needed :) ). However, I have come to a road that I have no knowledge of what so ever. I need to output this formatted table of the query to a text file on the server.
<?php
// Make a MySQL Connection
mysql_connect("hostname.net", "user", "pass") or die(mysql_error());
mysql_select_db("database") or die(mysql_error());
// Get all the data from the "example" table
$result = mysql_query("SELECT * FROM cards ORDER BY card_id")
or die(mysql_error());
echo "";
echo " Name AgeTitlebar ";
// keeps getting the next row until there are no more to get
while($row = mysql_fetch_array( $result )) {
// Print out the contents of each row into a table
echo "";
echo $row['card_id'];
echo "";
echo $row['title'];
echo "";
echo $row['item_bar'];
echo "";
}
echo "";
?>
I know I could use something similar to
<?php
$myFile = "test.txt";
$fh = fopen($myFile, 'w') or die("can't open file");
$stringData = "Bobby Bopper\n";
fwrite($fh, $stringData);
fclose($fh);
?>
but I am sure that it cant be the best solution. So I guess my question is does anyone know how to achieve this?
The nicest solution, particularly if you are short on memory, would be to put the writing into the loop:
$fh = fopen('cards.csv', 'w');
// keeps getting the next row until there are no more to get
while($row = mysql_fetch_array( $result )) {
fputcsv($fh, array($row['card_id'], $row['title'], $row['item_bar']), "\t");
}
fclose('cards.csv');
Note that I have used fputcsv to output the data in CSV format (using a tab as the delimiter). This should be easy to read by hand, and will also be easily understood by, for instance, a spreadsheet program. If you preferred a custom format, you should use fwrite as in your question.
Have a look at:
http://dev.mysql.com/doc/refman/5.0/en/select.html
especially:
[INTO OUTFILE 'file_name' export_options
| INTO DUMPFILE 'file_name'
| INTO var_name [, var_name]]
Something like this?
// Make sure the file exists, do some checks.
// Loop trough result set and append anything to the file.
while (false !== ($aRow = mysql_fetch_assoc($rResult))) {
$sCreateString = $aRow['field1'].';'.$aRow['field2'];
file_put_contents('example.txt', $sCreateString, FILE_APPEND);
}
// Done
If you need an exact dump of the database table, there are better options. (much better actually).
If you want to write a text file, then there's nothing wrong with what you've suggested.
There's lots of information in the PHP manual: http://www.php.net/manual/en/ref.filesystem.php
It depends entirely on how you want to store the data inside the file. You can create your own flat-file database format if you wish, and extract the data using PHP once you've read in the file.