baser-b Posted November 11, 2018 Share Posted November 11, 2018 So I am trying to write a script that reads a text file that contains words/definitions, prints the word/definition separately, sends those values to an MySQL database, then deletes those same values from the text file without leaving an empty line. I am having some trouble with getting it ALL to go down. I can get it to read/print the info I want, send it to the database, but deleting the values from the file isn't working. It just deletes the entire contents from the file. Here's the code: class Vocabulary { public $date; public $word; public $definition; private $file; private $list; private $output; function new() { $date = date("m/d/y"); $file = "vocab.txt"; $list = file($file); foreach ($list as $line) { $output = explode("-", $line, 2); $word = $output[0]; $definition = $output[1]; } queryMysql("INSERT INTO Vocabulary (word, definition, date) VALUES('$word', '$definition', '$date')"); echo "<br><strong>Word:</strong> " . $word; echo "<br><strong>Definition:</strong> " . $definition; $rewrite = fopen($file, "w+"); $delete = $output[0] . $output[1]; fwrite($rewrite, str_replace($delete, "", $list)); fclose($file); } } $vocab = new Vocabulary; echo $vocab->new(); I'm trying to figure out how I can send the values returned from the first "foreach", which would be the only result desired to be returned from the function, into a variable and "set" them. Because from what I believe is happening, its replacing the entire file with "" because its replacing $output[0] . $output[1] each time until there's no values left. So if I could set the values obtained from the first run of foreach loop then I could specifically delete those values from the file rather than $output[]. I dunno. I'm just beginning with PHP. Thanks. Quote Link to comment Share on other sites More sharing options...
requinix Posted November 11, 2018 Share Posted November 11, 2018 But, if you're reading all the lines from the file, then deleting all of those entries from the file, won't the end result be an empty file anyways? Quote Link to comment Share on other sites More sharing options...
Barand Posted November 11, 2018 Share Posted November 11, 2018 (edited) Several comments on that code All the variables in your new() function are local to that function, so why have the class properties defined? In fact, why have a class at all to run a single function? As you have no database connection defined I suspect you are either using mysql_ functions (which are now removed from PHP) or you create a connection for each query (also a no-no). When you are looping through your data you do nothing with that data, except overwriting the values. You need to write to the database within the loop. This bad practice unless using prepared statements (although even this can be slow (more about this later) When storing dates in a db table always use yyyy-mm-dd format (type DATE, DATETIME or TIMESTAMP). In my table I have define the date as TIMESTAMP DEFAULT CURRENT_TIMESTAMP so the date is automatically captured CREATE TABLE `vocabulary` ( `word` varchar(50) NOT NULL, `definition` varchar(50) DEFAULT NULL, `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`word`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Rewriting your class class Vocabulary { private $db; function __construct(PDO $db) // create object with a db connection { $this->db = $db; } function new($file) { $list = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $ins = $this->db->prepare("INSERT INTO vocabulary (word, definition) VALUES (?, ?)"); // prepare INSERT statement foreach ($list as $line) { $output = explode("-", $line); $ins->execute( $output ); } } } $db = pdoConnect('test') // create connection to test database $vocab = new Vocabulary($db) // pass db connection to object $vocab->new(vocab.txt); To test, I created a 'vocab.txt' file with 1000 definitions $vocab = ''; for ($w='a', $i=0; $i<1000; $i++, $w++) { $d = "Definition for $w"; $vocab .= "$w-$d\n"; } file_put_contents('vocab.txt', $vocab); The time taken was 45.539 seconds A second version of the new function wrote all the definitions in a single query in the form Quote INSERT INTO vocabulary (word, definition) VALUES ('word1', 'def1'), ('word2', 'def2'), ... , ('word1000', 'def1000') This code was function new2($file) { $list = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $params = $placeholders = []; foreach ($list as $line) { $output = explode("-", $line); $placeholders[] = "(?,?)"; array_push($params, $output[0], $output[1]); } $ins = $this->db->prepare("INSERT INTO vocabulary (word, definition) VALUES " . join(',', $placeholders)); // prepare INSERT statement $ins->execute( $params ); } The time taken using this version was 0.266 seconds Edited November 11, 2018 by Barand accidental post prior to completion Quote Link to comment Share on other sites More sharing options...
baser-b Posted November 11, 2018 Author Share Posted November 11, 2018 (edited) Well one about the why have a class for a single function, I am going to build upon the class that's just the one part I have a question about. A lot of the things in my code that don't make sense is because I am new at PHP and programming in general, and have not had more of an education than w3schools.com and reading other people's code and referencing it with php.net/manual/. I do have database functions defined but they are not directly relevant to the problem at hand, so I didn't include it. It is here: // Define MySQL variables define("SERVER", "localhost"); define("USERNAME", "admin"); define("PASSWORD", "??????"); define("DATABASE", "homepage"); // Connect to MySQL Database $connection = new mysqli(SERVER, USERNAME, PASSWORD, DATABASE); if ($connection->connect_error) { die($connection->connect_error); } function queryMysql($query) { global $connection; $result = $connection->query($query); if (!$result) die($connection->error); return $result; } Edited November 11, 2018 by Barand pwd removal Quote Link to comment Share on other sites More sharing options...
baser-b Posted November 11, 2018 Author Share Posted November 11, 2018 7 hours ago, requinix said: But, if you're reading all the lines from the file, then deleting all of those entries from the file, won't the end result be an empty file anyways? Well, I'm not necessarily trying to read ALL the entries from a file. My knowledge is limited. I know that file() turns a file into an array, but then I didn't know how to read a single line from the array produced, and now having thought it through, I figured that out, but it was a former experiment that had confused me when the $output[0] just returned a letter or something. But anyway this code does the same thing without getting the set of values I want from the array.... $file = "vocab.txt"; $source = file($file); $entry = explode("-", $source[0]); $word = $entry[0]; $definition = $entry[1]; Quote Link to comment Share on other sites More sharing options...
Barand Posted November 11, 2018 Share Posted November 11, 2018 3 minutes ago, baser-b said: Well, I'm not necessarily trying to read ALL the entries from a file. It might be a good idea to tell us what you are trying to rather than give us code that shows us what you are NOT trying to do. Quote Link to comment Share on other sites More sharing options...
baser-b Posted November 11, 2018 Author Share Posted November 11, 2018 (edited) Thanks for the edit, that wasn't my password though. Anyway, as an edit to my previous post: I am basically creating a part of a homepage script that will give me a vocabulary "word of the day" + definition as part of the overall setup. The point of the function I am trying to create is to serve 4 purposes: Read a random line from a text file containing a word and definition. Separate the two values. Print the two values as Word: $word and Definition: $definition. Store the values into an MySQL database that can be retrieved at another time. Delete the values from the text file without leaving a blank line I like learning new words and usually will put it in a textfile when I see it and get the definition later. Part of the purpose of the function is to specifically give me a word to meditate on each day and maybe also add a "memory game" or something on the page to help learn the word/definition rather than just accumulating words in a textfile. Edited November 11, 2018 by baser-b Needed to add more info Quote Link to comment Share on other sites More sharing options...
Barand Posted November 11, 2018 Share Posted November 11, 2018 (edited) Here's one way $db = pdoConnect('test'); class Vocabulary { private $db; function __construct(PDO $db) // create object with a db connection { $this->db = $db; } function new($file) { $list = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $rand_index = array_rand($list); $wotd = $list[$rand_index]; // get the word of the day list($word, $def) = explode('-', $wotd); $ins = $this->db->prepare("INSERT INTO vocabulary (word, definition, date) VALUES (?, ?, CURDATE() )"); // prepare INSERT statement $ins->execute( [$word, $def] ); unset($list[$rand_index]); // remove selected word def $text = ''; foreach ($list as $line) { $text .= $line . "\n" ; } file_put_contents($file, $text); // rewrite the file return [$word, $def]; } } $vocab = new Vocabulary($db); list($word, $definition) = $vocab->new('vocab.txt'); echo "Word of the day is <b>$word</b><br>Definition: <i>$definition</i>"; My 0.02 worth: Avoid using globals, it's too easy to inadvertently change a value that then has hidden repercussions throughout your code. Pass values as function arguments instead. As you are still learning, switch to PDO instead of mysqli, it's easier. Mysqli creates a different type of object depending on whether you use query() or prepare(). These objects have different methods to process what is essentially the same results (and some methods only work depending on your php setup). With pdo you have the one set of methods. If you do use mysqli, call mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT); before you connect. This will save you from having to check if every operation was successful as it will automatically throw an error. With PDO, use the options when connectiong EG function pdoConnect($database) { $dsn = "mysql:dbname=$database; host=".HOST."; charset=utf8"; $db = new pdo($dsn, USERNAME, PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); return $db; } Edited November 11, 2018 by Barand Clean up the code Quote Link to comment Share on other sites More sharing options...
benanamen Posted November 11, 2018 Share Posted November 11, 2018 Based on your objective you should just import a dictionary and then use code to randomly display the data. I found one Dictionary DB at https://sourceforge.net/projects/mysqlenglishdictionary/ Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.