PHP SQLite - prepared statement misbehaves? - php

I have the following SQLite table
CREATE TABLE keywords
(
id INTEGER PRIMARY KEY,
lang INTEGER NOT NULL,
kwd TEXT NOT NULL,
count INTEGER NOT NULL DEFAULT 0,
locs TEXT NOT NULL DEFAULT '{}'
);
CREATE UNIQUE INDEX kwd ON keywords(lang,kwd);
Working in PHP I typically need to insert keywords in this table, or update the row count if the keyword already exists. Take an example
$langs = array(0,1,2,3,4,5);
$kwds = array('noel,canard,foie gras','','','','','');
I now these data run through the following code
$len = count($langs);
$klen = count($kwds);
$klen = ($klen < $len)?$klen:$len;
$sqlite = new SQLite3('/path/to/keywords.sqlite');
$iStmt = $sqlite->prepare("INSERT OR IGNORE INTO keywords (lang,kwd)
VALUES(:lang,:kwd)");
$sStmt = $sqlite->prepare("SELECT rowid FROM keywords WHERE lang = :lang
AND kwd = :kwd");
if (!$iStmt || !$sStmt) return;
for($i=0;$i < $klen;$i++)
{
$keywords = $kwds[$i];
if (0 === strlen($keywords)) continue;
$lang = intval($langs[$i]);
$keywords = explode(',',$keywords);
for($j=0;$j < count($keywords);$j++)
{
$keyword = $keywords[$j];
if (0 === strlen($keyword)) continue;
$iStmt->bindValue(':kwd',$keyword,SQLITE3_TEXT);
$iStmt->bindValue(':lang',$lang,SQLITE3_INTEGER);
$sStmt->bindValue(':lang',$lang,SQLITE3_INTEGER);
$sStmt->bindValue(':kwd',$keyword,SQLITE3_TEXT);
trigger_error($keyword);
$iStmt->execute();
$sqlite->exec("UPDATE keywords SET count = count + 1 WHERE lang =
'{$lang}' AND kwd = '{$keyword}';");
$rslt = $sStmt->execute();
trigger_error($sqlite->lastErrorMsg());
trigger_error(json_encode($rslt->fetchArray()));
}
}
which generates the following trigger_error output
Keyword: noel
Last error: not an error
SELECT Result: {"0":1,"id":1}
Keyword: canard
Last Error: not an error
SELECT Reult:false
Keyword:foiegras
Last Error: not an error
SELECT Result: false
From the SQLite command line I see that the three row entries are present and correct in the table with the id/rowid columns set to 1, 2 and 3 respectively. lastErrorMsg does not report an error and yet two of the three $rslt->fetchArray() statements are returning false as opposed to an array with rowid/id attributes. So what am I doing wrong here?
I investigated this a bit more and found the underlying case. In my original code the result from the first SQLite3::execute - $iStmt-execute() - was not being assigned to anything. I did not see any particular reason for fetching and interpreting that result. When I changed that line of code to read $rslt = $iStmt->execute() I got the expected result - the rowid/id of the three rows that get inserted was correctly reported.
It is as though internally the PHP SQLite3 extension buffers the result from SQLiteStatement::execute function calls. When I was skipping the assignment my next effort at running such a statement, $sStmt->execute() was in effect fetching the previous result. This is my interpretation without knowing the inner workings of the PHP SQLite3 extension. Perhaps someone who understands the extension better would like to comment.

Add $rslt = NONE; right after trigger_error(json_encode($rslt->fetchArray())); and the correct results appear.
FetchArray can only be called once and somehow php is not detecting that the variable has changed. I also played with changing bindValue to bindParam and moving that before the loop but that is unrelated to the main issue.
It is my opinion that my solution should not work unless there is a bug in php. I am too new at the language to feel confident in that opinion and would like help verifying it. Okay, not a bug, but a violation of the least surprise principle. The object still exists in memory so without finalizing it or resetting the variable, fetch array isn't triggering.

Related

MYSQL/Laravel LIKE behaving unexpectedly

I have a bunch of mathematical tasks which I want to filter through a textbox.
For example:
4*1 should return 4*1, 4*10, 4*11, ...
4*11 should return 4*11
To do that I wrote this piece of code:
$operator = DB::connection()->getPdo()->quote("{$operator}");
$operand2 = DB::connection()->getPdo()->quote("{$operand2}%");
DB::table('tasks')
->select(DB::raw('*'))
->whereRaw("operand1 = {$operand1} AND operator = {$operator} AND CAST(operand2 AS CHAR(50)) LIKE {$operand2}")
->get();
The results of this are pretty unexpected und unpredictable.
When I type 4*5 I get 4*{any operand}
When I type 4*12 I get 4*1, 4*10, 4*11, 4*12
UPDATE/SOLUTION
It turned out that it didn't have anything to with MySQL or Laravel. It was an error in JS. I used the keypress event instead of keyup. This way always the last typed digit was lost.

Loop Making PHP output and browser-viewed source code vanish

I recently started coding a script meant for html output that (hopefully) will reduce some busy work at my job. It is a script adapted from a functional script I wrote in python, but I do not think that is the issue.
I have the following code at the start of the php script to identify errors:
ini_set('display_errors', 1);
error_reporting(E_ALL ^ E_NOTICE);
I have put the program on a server and attempted to run it. My first problem is that partway through the program, it starts dumping the source code (minus HTML tags) to the window partway through an if statement as such:
$moonSet[0]){
$t = 3;
} # Case 4, set time greater than rise time
else {
$t = 4;
}
For reference, the actual section of code interrupted is as such:
# Case 1, no rise time on current date
if ($moonRise[0] == 0){
$t = 1;
} # Case 2, no set time on current/next date
elseif ($moonSet[0] == 0){
$t = 2;
} # Case 3, rise time greater than set time
elseif ($moonRise[0] > $moonSet[0]){
$t = 3;
} # Case 4, set time greater than rise time
else {
$t = 4;
}
I believe the version of php used on the server is at least PHP 5.x, as the source code is dumped to the window when the html coding uses <??> instead of <?php?>. The problem is that when I use <?php?> all the output vanishes--the HTML tags included. Looking at the source code, it only shows a 1 to indicate the first line of code, suggesting that no code is actually in the file. This only happens when I use <?php?> instead of <??>.
I then tried to gradually step through the code to identify why, one, the code suddenly interrupts the if statement, and two, why using <?php?> torches the output.
What I ended up discovering is that the <?php?> code works just fine until I added in a loop. The program uses a MySQL query, and from what I can tell, the query worked just fine. The program executed, output at both the beginning and end of the test code was displayed to screen.
The SQL code is as such:
$connection = mysql_connect("localhost", "webuser", "webuser");
mysql_select_db("dbAstro", $connection);
$queryTides = "SELECT tideDateTime, tideHeight, tideHorL FROM tblTides WHERE DATE(tideDateTime) BETWEEN '$targetDate[0] 00:00:00' AND '$targetDate[2] 23:59:59' ORDER BY tideDateTime";
$querySun = "SELECT sunDate, sunRise, sunSet FROM tblSunRiseSet WHERE DATE(sunDate) BETWEEN '$targetDate[0] 00:00:00' AND '$targetDate[2] 23:59:59' ORDER BY sunDate";
$queryMoon = "SELECT moonDate, moonRise, moonSet FROM tblMoonRiseSet WHERE DATE(moonDate) BETWEEN '$targetDate[0] 00:00:00' AND '$targetDate[2] 23:59:59' ORDER BY moonDate";
$queryTwi = "SELECT twilightDate, twilightBeg, twilightEnd FROM tblCivilTwilight WHERE DATE(twilightDate) BETWEEN '$targetDate[0] 00:00:00' AND '$targetDate[2] 23:59:59' ORDER BY twilightDate";
#Query results stored in separate result locations for later reference.
$resultTi = mysql_query($queryTides, $connection);
$resultSu = mysql_query($querySun, $connection);
$resultMo = mysql_query($queryMoon, $conneciton);
$resultTwi = mysql_query($queryTwi, $connection);
The difference between using the <?php?> and <??> tags so far is that <??> will not display a printf('') command. <?php?> displayed the printf('') command, but with a message that a null value is in the database--which there are some null values in the database.
The problem is when the script enters a loop. Upon putting a loop command, either while or for, the <?php?> script vanishes from both the output and when viewing the source code in a browser. <??> as a tag still outputs the HTML, but does not output any of the php commands--a basic printf('') or an echo command.
I want to stress that it does this with any loop--not just a while loop that searched the SQL queries (the intended goal, shown abbreviated below):
$b = 0;
while ($astroRow = mysql_fetch_assoc($resultTi)) {
$tideTime[$b] = date_format("$astroRow[tideDateTime]", "hi");
$b++;
}
When I attempted to replace the loop with something extremely basic, like this:
for ($a = 0; $a < 2; $a++) {
echo $a;
}
the same pattern occurred. One would start dumping output to screen or show no output from php, and the <?php?> tags would show no code or output whatsoever.
I am at a loss. I do not know what the problem is, and attempting to search help sites has not led me to an answer to my problem. Would anyone have an idea what exactly is going on?

How do I validate a PHP integer within a variable?

I have integrated Yelp reviews into my directory site with each venue that has a Yelp ID returning the number of reviews and overall score.
Following a successful MySQL query for all venue details, I output the results of the database formatted for the user. The Yelp element is:
while ($searchresults = mysql_fetch_array($sql_result)) {
if ($yelpID = $searchresults['yelpID']) {
require('yelp.php');
if ( $numreviews > 0 ) {
$yelp = '<img src="'.$ratingimg.'" border="0" /> Read '.$numreviews.' reviews on <img src="graphics/yelp_logo_50x25.png" border="0" /><br />';
} else {
$yelp = '';
}
} //END if ($yelpID = $searchresults['yelpID']) {
} //END while ($searchresults = mysql_fetch_array($sql_result)) {
The yelp.php file returns:
$yrating = $result->rating;
$numreviews = $result->review_count;
$ratingimg = $result->rating_img_url;
$url = $result->url;
If a venue has a Yelp ID and one or more reviews then the output displays correctly, but if the venue has no Yelp ID or zero reviews then it displays the Yelp review number of the previous venue.
I've checked the $numreviews variable type and it's an integer.
So far I've tried multiple variations of the "if ( $numreviews > 0 )" statement such as testing it against >=1, !$numreviews etc., also converting the integer to a string and comparing it against other strings.
There are no errors and printing all of the variables returned gives the correct number of reviews for each property with venues having no ID or no reviews returning nothing (as opposed to zero). I've also compared it directly against $result->review_count with the same problem.
Is there a better way to make the comparison or better format of variable to work with to get the correct result?
EDIT:
The statement if ($yelpID = $searchresults['yelpID']) { is not operating as it should. It is identical to other statements in the file, validating row contents which work correctly for their given variable, e.g. $fbID = $searchresults['fbID'] etc.
When I changed require('yelp.php'); to require_once('yelp.php'); all of the venue outputs changed to showing only the first iterated result. Looking through the venues outputted, the error occurs on the first venue after a successful result which makes me think there is a pervasive piece of code in the yelp.php file, causing if ($yelpID = $searchresults['yelpID']) { to be ignored until a positive result is found (a yelpID in the db), i.e. each venue is correctly displayed with a yelp number of reviews until a blank venue is encountered. The preceding venues' number of reviews is then displayed and this continues for each blank venue until a venue is found with a yelpID when it shows the correct number again. The error reoccurs on the next venue output with no yelpID and so on.
Sample erroneous output: (line 1 is var_dump)
string(23) "bayview-hotel-bushmills"
Bayview Hotel
Read 3 reviews on yelp
Benedicts
Read 3 reviews on yelp (note no var_dump output, this link contains the url for the Bayview Hotel entry above)
string(31) "bushmills-inn-hotel-bushmills-2"
Bushmills Inn Hotel
Read 7 reviews on yelp
I suspect this would be a new question rather than clutter/confuse this one further?
END OF EDIT
Note: I'm aware of the need to upgrade to mysqli but I have thousands of lines of legacy code to update. For now I'm working on functionality before reviewing the code for best practice.
Since the yelp.php is sort of a blackbox; the best explanation for this behavior would be that it only set's those variables if it finds a match. Updating your code to this should fix that:
unset($yrating, $numreviews, $ratingimg, $url);
require('yelp.php');
I also noticed this peculiar if-statement, do you realize that's an assignment or is this a copy/paste error? If you want to test (that's what if is for)
if ($yelpID == $searchresults['yelpID']) {

PHP the same strings but yet not the same

I use PHPExcel package in order to import data from .xls files to my database. From time to time the file is updated so I have to import it again. Before the import itself, I check if database already contains any of data included in .xls file.
In most cases, it works - data already included in DB is omitted, but still there are some values that are duplicated.
Here's what I do:
1. Query to DB: SELECT * FROM Table1, fetching the result to an array.
2. PHPExcel usage, get row value to a variable, check if the value already exists in the array
3. If yes - skip, if no - add to DB.
But there's a value "The name (xxx yyy zzz)" that IS included in the array (I used if ($array[0] == "The name (xxx yyy zzz)") and it returned true), but still PHP function array_search couldn't find it.
I used trim and still nothing. var_dump of variable, the actual value and the index value was the same. similar_text($array[0], "The name (xxx yyy zzz)") returned 2.
Please help, I ran out of ideas.
You would be better off using MySQL to do this:
ALTER IGNORE TABLE your-table ADD UNIQUE INDEX idx ( uniqueField, orFields );
This will remove all duplicated where the field or fields are the same. Drop the index once you are done:
ALTER TABLE your-table DROP INDEX idx
2 known issues:
1
I've once had a problem that is a bit similar. The problem ended up being that the imported data was read with an incorrect encoding. It lead to the following:
echo $str1; // output: foo
echo $str2; // output: foo
echo $str1 == $str2 ? "The same" : "Not the same"; // output: Not the same
I was only to understand it after I did the following:
for($i = 0; $i < strlen($str1); $i++) echo ord($str1[$i])." "; // 102 111 111
for($i = 0; $i < strlen($str2); $i++) echo ord($str2[$i])." "; // 102 0 111 0 111 0
I am guessing that you are running into something similar.
2
Another possibility is as suggested in the comments, that you have HTML in your string. To get that out in the open, do the following:
echo htmlspecialchars($str1); // foo
echo htmlspecialchars($str2); // <span>foo</span>
And/or view the source of your HTML page in the browser.

PHP/MYSQL - Insert multiple rows into one column, works via phpmyadmin but only partially via myqli prepared statement?

Using a mysqli prepared statement I would like to insert an array into a mysql database table.
Being aware that bind-param and arrays do not go together, we would like to write the query in php first, then process this as a prepared statement:
$tagQuery = "INSERT INTO word_tags(speaks) VALUES ";
// Count total array values
$icoderayInsideCount = count($icoderayInside);
foreach ($icoderayInside as $icoderayInsideKey=>$icoderayInsideValue)
{
// Last value
// Currrent Array Key Total / Last Array Value
if ($icoderayInsideKey == $icoderayInsideCount)
{
$tagQuery .= "('$icoderayInsideValue')";
}
// All other values
else
{
$tagQuery .= "('$icoderayInsideValue'), ";
}
}
// Send array (keywords) to database
if ($stmt2 = $link2->prepare($tagQuery))
{
if (!$stmt2->execute())
{
// #2 If it can prepare but can't execute, why?
echo "Error {$link2->errno} : {$link2->error} (Cant execute?) <br/>";
// Dump query to check the end result
var_dump($tagQuery);
exit();
}
$stmt2->close();
}
else
{
// #1 If it cant prepare, why?
echo "Error {$link2->errno} : {$link2->error} (Cant prepare?)";
exit();
}
When i run this via PHP / Server i get:
Error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '('DONGLES'),' at line 1 (Cant prepare?)
So, the statement prepares but is not being executed.
The value of the generated query, $tagQuery is:
INSERT INTO word_tags(speaks) VALUES ('PMP3670B_BK'), ('PRESTIGIO'), ('MULTIPAD'), ('7"'), ('800X480'), ('1GHZ'), ('ARM'), ('CORTEX'), ('A8'), ('CPU'), ('512MB'), ('DDR3'), ('DRAM'), ('ANDROID'), ('4.1'), ('JELLY'), ('BEAN'), ('MALI'), ('400'), ('MP'), ('GPU'), ('VIDEO'), ('4GB'), ('INTERNAL'), ('FLASH'), ('MEMORY'), ('SUPPORT'), ('32GB'), ('SDHC/SD'), ('USB/WI-FI/HEADSET'), ('PORT'), ('LITHIUM'), ('POLYMER'), ('BLACK'), ('HDMI'), ('OUTPUT'), ('UPTO'), ('1080'), ('HD'), ('USB2.0'), ('MINI'), ('HIGH'), ('SPEED'), ('FOR'), ('3G'), ('DONGLE'), ('OTG'), ('CABLE'), ('INCLUDED')
The fourth value from the end is('DONGLE') which is what the error message is complaining about.
When i run this exact same query through phpmyadmin there is no error involved.
What i assume is happening, is that there is some kind of length limit involved within creating a prepared statement... Or something to this effect.
Have scratched my brains for hours now to try to solve this and have not found any relating information.
If anyone could offer some assistance / advice / indication / input or otherwise as to what the conflict of problem may be within this, it would be GREATLY appreciated.
Thanks so much for the time and effort in readying through this!
EDIT:
#Mihai - Thanks for the thought.
It seems that the word dongle does have something string to it. In the original string, before being parsed to an array, it looks like this: DONGLE,
I run preg_replace to remove this comma from the string before parsing it to an array:
$icode = preg_replace('#,#', '', $icode);
Then into an array:
$icoderayInside = explode(" ", $icode);
Still cannot think of any reason this would cause a conflict as the output string, the query is as i have previously stated and includes no comma, or anything... Any would be greatly appreciated!
EDIT 2:
#ShadyAtef
Original input is stored in mysql as varchar, latin_general_ci:
PRESTIGIO MULTIPAD, 7" 800X480, 1GHZ ARM CORTEX A8 CPU, 512MB DDR3 DRAM, ANDROID 4.1 JELLY BEAN, MALI 400 MP GPU, VIDEO, 4GB INTERNAL FLASH MEMORY, SUPPORT 32GB SDHC/SD, USB/WI-FI/HEADSET PORT, LITHIUM POLYMER, BLACK, HDMI OUTPUT UPTO 1080 HD, USB2.0 MINI HIGH SPEED PORT FOR 3G DONGLE, OTG CABLE INCLUDED
Brought into php then processed to an array with additional requirements:
// Convert Var a + b to String
$icode = $itemCode . ' ' . $description;
// Clean of Unwanteds
$icode = preg_replace('#,#', '', $icode);
$icode = preg_replace('#\(#', '', $icode);
$icode = preg_replace('#\)#', '', $icode);
// Creates array from sting
$icoderayInside = explode(" ", $icode);
// Remove array duplicates
$icoderayInside = array_unique($icoderayInside);
Before being built into the query. Any assistance would be GREATLY appreciated!
EDIT 3:
#ShadyAtef
// Currrent Array Key Total / Last Array Value
if ($icoderayInsideKey == $icoderayInsideCount)
{
// dump here shows:
$icoderayInsideKey == 49
$icoderayInsideCount == 49
}
This was really tricky,but I got it : The tricky wrong part is that
if ($icoderayInsideKey == $icoderayInsideCount)
It should be
if ($icoderayInsideKey == ($icoderayInsideCount-1))
Because the last key in the array equals to the array (length -1) So you should change your if condition

Categories