I'm trying to run a SQL query, and it is working correctly in phpMyAdmin, but whe running it in PHP, the query comes back very wonky. The following query yields two different results:
SELECT `stock_ticker`, `stock_simpleName`, `stock_logo`
FROM `stocks`
WHERE stock_simpleName REGEXP'^c'
I get the following results in phpMyAdmin (Which is correct):
stock_simpleName
----------------------
Coca-Cola
Campbell's
ConAgra Foods
However, in PHP it comes out really weird:
stock_simpleName
-----------------------
Coca-Cola
MasterCard
Campbell's
Microsoft
The Walt Disney Company
PepsiCo
The Hershey Company
Proctor & Gamble
ConAgra Foods
...etc...
Why is this happening? This doesn't make any sense. Is it due to a server setting in PHP or some form of encoding or whatnot?
EDIT:
Here is my PHP Code:
The sub-model class (the creator of the pieces):
public function allOtherSearchResults($query, $dontQuery = null) {
$name = "stocks";
$where = "stock_simpleName REGEXP'^" . $query . "'";
$cols = array("stock_ticker", "stock_simpleName", "stock_logo");
$limit = 5;
return $this->select($name, $cols, $where, $limit);
}
The main-model class (this runs the query):
public function select($tableName, $columns, $where = null, $limit = null) {
global $purifier;
// Make columns SQL friendly
$cols = "`";
$cols .= implode("`, `", $columns);
$cols .= "`";
$table = "`" . $tableName . "`";
if (!empty($where)) {
$where = " WHERE " . $where;
}
// Check limit
if (!empty($limit)) {
$limit = " LIMIT $limit";
}
// SQL CODE
$sql = "SELECT " . $cols . " FROM " . $table . $where . $limit;
// SQL DEBUGGING IF CODE RETURNS BOOLEAN ERROR
echo $sql . "<br>";
$query = $this->conn->query($sql);
// Store the value in a variable called table with an array of that table's name followed by it's values
// EX: $model->table["bands"]["band_name"]
//
// Accessible by the individual page/directory's controller's
while($row = $query->fetch_assoc()){
// Store values as $model->table["tableName"]["columnName"]["index (usually 0)"]
foreach ($row as $key => $val) {
$this->data[$tableName][$key][] = $row[$key];
}
}
// Loop through results to clean them
// Foreach loops through each column
// Make sure the table isn't empty (i.e. login returns an error)
if (!empty($this->data[$tableName])) {
foreach ($this->data[$tableName] as $key => $tableArray) {
// For loop goes through each value in a certain row
for ($i = 0; $i < count($tableArray); $i++) {
// Convert from data variable to table after HTML PURIFIER
$this->table[$tableName][$key][$i] = $purifier->purify($tableArray[$i]);
}
}
}
// Declare the array after loop has finished for use in view
$this->table;
if (!empty($this->table)) {
return true;
}
}
And it gives me the same SQL output as above. I am not sure if there is a different interpretation of certain characters in PHP versus the standard MySQL in phpMyAdmin. Has anyone even had this problem before?
I'm guessing, that there is a problem wiht ^ character.
Try to set proper connection & result encoding, eq.
$this->conn->query("MYSQL SET NAMES utf8");
$this->conn->query("MYSQL SET CHARACTER SET utf8");
Also, check if your php script file is saved in UTF-8 encoding.
Moreover, you should consider of using prepared statement (even to prevent SQL Injection):
$this->conn->prepare("SELECT * FROM `stocks` WHERE `stock_simpleName` REGEXP ?");
$this->conn->bind_param("s", "^c");
$this->conn->execute();
$query = $this->conn->get_result();
Related
I have a web application and I'm trying to modify one of the queries. The query fetches information (from a table named voyage_list) and returns various fields.
I want to modify the query so that it is based on certain filters the user applies (which will be placed in the URL).
I can't get the query to work in the web application, but if I copy the query and execute it directly within PHPMyAdmin, it works fine.
$vesselFilter = $_GET['vesselFilter'];
$vesselArray = explode(',', $vesselFilter);
$arrayCount = count($vesselArray);
$sqlExtend = ' status = 1 AND';
foreach ($vesselArray as $value) {
$i = $i + 1;
$sqlExtend .= " vesselID = '$value'";
if ($i < $arrayCount){
$sqlExtend .= " OR";
}
}
$newQuery = "SELECT * FROM voyage_list WHERE" . $sqlExtend;
echo $newQuery;
$query = $db->query($newQuery)->fetchAll();
I appreciate the above is pretty messy, but it's just so I can try and figure out how to get the query to work.
Any help would be greatly appreciated!
Thanks
That query probably doesn't return what you think it does. AND takes precedence over OR, so it will return the first vessel in the list if the status is 1, and also any other vessel in the list, regardless of status.
You'd do better to create a query with an IN clause like this:
SELECT * FROM voyage_list WHERE status = 1 AND vesselID IN(8,9,10)
Here's some code to do just that:
$vesselFilter = $_GET['vesselFilter'];
// Validate data. Since we're expecting a string containing only integers and commas, reject anything else
// This throws out bad data and also protects against SQL injection.
if (preg_match('/[^0-9,]/', $vesselFilter)) {
echo "Bad data in input";
exit;
}
// filter out any empty entries.
$vesselArray = array_filter(explode(',', $vesselFilter));
// Now create the WHERE clause using IN
$sqlExtend = 'status = 1 AND vesselID IN ('.join(',', $vesselArray).')';
$newQuery = "SELECT * FROM voyage_list WHERE " . $sqlExtend;
echo $newQuery;
$query = $db->query($newQuery)->fetchAll();
var_dump($query);
I am using mysql as my database and php as server side language.
As we know that we can select data from database using select query.
Below example is important!!
select * from table
select name from table
select name,salary from table where salary > 10000
etc..........
now, for different select query of a table we need different select method. because every time select * is not good because it takes a huge time.
Now, My Question is how write dynamic single get method of a single table by which we can achieve our requirement (shown in example...)?
I will pass the array of parameters in the argument of the function.. for ex. in php
public get($arr)
{
//code goes here
}
I want to fetch the $arr and want to change the sql dynamically..
Don't want any join query just simple select as shown in above..
Depending on how you want to do it, you can do something like this:
public get($arrfield, $arrtable, $arrwhere)
{
$str = "SELECT " . $arrfield . " FROM " . $arrtable . " WHERE " . $arrwhere;
return $str;
// You can return the query string or run the query and return the results
}
Trust me, to write all three queries is not that too hard a job that have to be avoided at any cost.
Please, do not obfuscate a precious SQL language into unreadable gibberish. Not to mention innumerable security breaches of your approach.
What you should think of is a function that lets you to use parameters. Thus, better make our function like this
function mysqli($mysqli, $query, $params, $types = NULL)
{
$statement = $mysqli->prepare($select);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement;
}
and run your every query as is, only providing placeholders instead of variables
select * from table:
you'll never need a query like this
select name from table
$names = mysqli($db, "select name from table")->get_result->fetch_all();
`select name,salary from table:
$stmt = mysqli($db, "select name from table where salary > ?", [10000]);
$names = $stmt->get_result->fetch_all();
See - the query itself is the least code portion. Your concern should be not SQL but useless reprtitive parts of PHP code used to run a query and to fetch the data.
Here is the structure of the dynamic query.Please add required validation.You can add 'Or' clause also.On the basis of parameter or data type you can do it. Like
public SelectTable($arrfield, $table, $arrwhere, $arrgroup)
{
if(!empty($arrfield))
{
$fields = implode('`,`',$arrfield);
}
else
{
$fields = '*';
}
if(!empty($arrwhere))
{
foreach($arrwhere as $fieldName=>$fieldValue)
{
if(is_array($fieldValue))
{
$cond .= "`fieldName` in (". implode(',',$fieldValue) );
}
else
$cond .= "`fieldName` = '" . addslashes($fieldValue)."'";
}
}
else
{
$cond = '1';
}
if(!empty($arrgroup))
{
$groupBy .= " group by ";
foreach($arrgroup as $field=>$value)
{
$groupBy .= $field . " " . $vale;
}
}
}
$str = "SELECT " . $fields . " FROM " . $table . " WHERE " . $cond . $groupBy;
return $str;
// You can return the query string or run the query and return the results
}
I built PHP 2 year ago and now i want to change all about database to PDO,i have some problem with update table. I use this function to update table.
public function update($tabel, $fild = null ,$where = null)
{
$update = 'UPDATE '.$tabel.' SET ';
$set=null; $value=null;
foreach($fild as $key => $values)
{
$set .= ', '.$key. ' = :'.$key;
$value .= ', ":'.$key.'":"'.$values.'"';
}
$update .= substr(trim($set),1);
$json = '{'.substr($value,1).'}';
$param = json_decode($json,true);
if($where != null)
{
$update .= ' WHERE '.$where;
}
$query = parent::prepare($update);
$query->execute($param);
$rowcount = $query->rowCount();
return $rowcount;
}
everything work fine using this
$updatefild = array('count' => 20);
$where = "id = '123'";
echo $db->update("mytable",$updatefild, $where);
but i get problem when i want to update row with existing row, in mysql_query I usually use
mysql_query("update mytable set count=count+1 where id='123'");
how i achieve that use PDO ?
thanks
First, why are you using JSON just to decode it into an array? That is confusing.
Secondly, if you were trying to add a number to an existing field, you don't even need prepare().
You could just do
PDO->query("update mytable set count=count+".intval($int)." where id='123'");
If you were doing prepare, you could do:
$stmt = PDO->prepare("update mytable set count=count+:count where id='123'");
$stmt->execute(array(':count' => 1));
or
$stmt = PDO->prepare("update mytable set count=count+? where id='123'");
$stmt->execute(array(1));
Edit: You wouldn't be able to do it with how your function is written as you can't bind column names. PDO will quote it as a standard string. You would have to find a work around, possibly including the =count in the field somehow.
I have a form that is going to be used to search through a table of support tickets.
the user can search from a few difficult optional fields.
Date (to/from)
Ticket Status
Engineer
Ticket Contact
I'm wondering what is the best way to deal with optional search filters. So I have a query that takes in parameters from the user. So if the user searches using both the from and to dates then the query would want to include BETWEEN. So do I have to write a different query for if the user searches for only from. or another query when the user has not added any date parameters? Then what if the status dropdown is blank? Is that another query?
Any help to clear this up would be great!
Jonesy
Build your query in parts. Start with whatever is constant in your query, and add on more SQL depending on what extra conditions:
$query = "SELECT ...
FROM ...
WHERE [where conditions that are always going to be present]";
if (isset($_POST['date_from']) && isset($_POST['date_to']))
{
$query .= ... // query code for dealing with dates
}
if (isset($_POST['status']))
{
$query .= ... // deal with status
}
// etc.
// Once you have your query fully built, execute it
$result_set = mysql_query($query);
This code is obviously just a skeleton, but that's how I would construct my query.
Hard to say without knowing what sort of DB abstraction you're using, but assuming you're hand-writing the SQL, it's fairly simple, just build up sections of your where clause individually for each variable. (Assuming here that your vars are already escaped/quoted.)
$where_clause = array();
if (!empty($date_from)) {
$where_clause[] = "table.date >= $date_from";
}
if (!empty($date_to)) {
$where_clause[] = "table.date <= $date_to";
}
if (!empty($status)) {
$where_clause[] = "status = $status";
}
$query = 'select * from table where ' . join(' and ', $where_clause);
This is an elegant way that I use alot and wish will help you too:
$q = 'SELECT * FROM Users';
$buildQ = array();
if (empty($idOrName) === false) {
$buildQ[] = '(userid = "' . $idOrName . '" OR username LIKE "%' . $idOrName. '%")';
}
if (empty($nickname) === false) {
$buildQ[] = 'nickname="' . $nickname . '"';
}
if (empty($salary) === false) {
$buildQ[] = 'salary="' . $salary . '"';
}
// ... any other criterias like above if statements
if (count($buildQ) === 1) {
$q .= ' WHERE ' . $buildQ[0];
} else if (count($buildQ) > 1) {
$count = 0;
foreach ($buildQ as $query) {
if ($count === 0) {
$q .= ' WHERE ' . $query;
} else {
$q .= ' AND ' . $query;
}
$count++;
}
}
I think it would be better if You generate query dynamically at runtime based on which fields are filled. So You could make some helper which appends specific query fragments if only one date is passed and the other one is null, or when both are passed and so on.
Long before I knew anything - not that I know much even now - I desgined a web app in php which inserted data in my mysql database after running the values through htmlentities(). I eventually came to my senses and removed this step and stuck it in the output rather than input and went on my merry way.
However I've since had to revisit some of this old data and unfortunately I have an issue, when it's displayed on the screen I'm getting values displayed which are effectively htmlentitied twice.
So, is there a mysql or phpmyadmin way of changing all the older, affected rows back into their relevant characters or will I have to write a script to read each row, decode and update all 17 million rows in 12 tables?
EDIT:
Thanks for the help everyone, I wrote my own answer down below with some code in, it's not pretty but it worked on the test data earlier so barring someone pointing out a glaring error in my code while I'm in bed I'll be running it on a backup DB tomorrow and then on the live one if that works out alright.
I ended up using this, not pretty, but I'm tired, it's 2am and it did its job! (Edit: on test data)
$tables = array('users', 'users_more', 'users_extra', 'forum_posts', 'posts_edits', 'forum_threads', 'orders', 'product_comments', 'products', 'favourites', 'blocked', 'notes');
foreach($tables as $table)
{
$sql = "SELECT * FROM {$table} WHERE data_date_ts < '{$encode_cutoff}'";
$rows = $database->query($sql);
while($row = mysql_fetch_assoc($rows))
{
$new = array();
foreach($row as $key => $data)
{
$new[$key] = $database->escape_value(html_entity_decode($data, ENT_QUOTES, 'UTF-8'));
}
array_shift($new);
$new_string = "";
$i = 0;
foreach($new as $new_key => $new_data)
{
if($i > 0) { $new_string.= ", "; }
$new_string.= $new_key . "='" . $new_data . "'";
$i++;
}
$sql = "UPDATE {$table} SET " . $new_string . " WHERE id='" . $row['id'] . "'";
$database->query($sql);
// plus some code to check that all out
}
}
Since PHP was the method of encoding, you'll want to use it to decode. You can use html_entity_decode to convert them back to their original characters. Gotta loop!
Just be careful not to decode rows that don't need it. Not sure how you'll determine that.
I think writing a php script is good thing to do in this situation. You can use, as Dave said, the html_entity_decode() function to convert your texts back.
Try your script on a table with few entries first. This will make you save a lot of testing time. Of course, remember to backup your table(s) before running the php script.
I'm afraid there is no shorter possibility. The computation for millions of rows remains quite expensive, no matter how you convert the datasets back. So go for a php script... it's the easiest way
This is my bullet proof version. It iterates over all Tables and String columns in a database, determines primary key(s) and performs updates.
It is intended to run the php-file from command line to get progress information.
<?php
$DBC = new mysqli("localhost", "user", "dbpass", "dbname");
$DBC->set_charset("utf8");
$tables = $DBC->query("SHOW FULL TABLES WHERE Table_type='BASE TABLE'");
while($table = $tables->fetch_array()) {
$table = $table[0];
$columns = $DBC->query("DESCRIBE `{$table}`");
$textFields = array();
$primaryKeys = array();
while($column = $columns->fetch_assoc()) {
// check for char, varchar, text, mediumtext and so on
if ($column["Key"] == "PRI") {
$primaryKeys[] = $column['Field'];
} else if (strpos( $column["Type"], "char") !== false || strpos($column["Type"], "text") !== false ) {
$textFields[] = $column['Field'];
}
}
if (!count($primaryKeys)) {
echo "Cannot convert table without primary key: '$table'\n";
continue;
}
foreach ($textFields as $textField) {
$sql = "SELECT `".implode("`,`", $primaryKeys)."`,`$textField` from `$table` WHERE `$textField` like '%&%'";
$candidates = $DBC->query($sql);
$tmp = $DBC->query("SELECT FOUND_ROWS()");
$rowCount = $tmp->fetch_array()[0];
$tmp->free();
echo "Updating $rowCount in $table.$textField\n";
$count=0;
while($candidate = $candidates->fetch_assoc()) {
$oldValue = $candidate[$textField];
$newValue = html_entity_decode($candidate[$textField], ENT_QUOTES | ENT_XML1, 'UTF-8');
if ($oldValue != $newValue) {
$sql = "UPDATE `$table` SET `$textField` = '"
. $DBC->real_escape_string($newValue)
. "' WHERE ";
foreach ($primaryKeys as $pk) {
$sql .= "`$pk` = '" . $DBC->real_escape_string($candidate[$pk]) . "' AND ";
}
$sql .= "1";
$DBC->query($sql);
}
$count++;
echo "$count / $rowCount\r";
}
}
}
?>
cheers
Roland
It's a bit kludgy but I think the mass update is the only way to go...
$Query = "SELECT row_id, html_entitied_column FROM table";
$result = mysql_query($Query, $connection);
while($row = mysql_fetch_array($result)){
$updatedValue = html_entity_decode($row['html_entitied_column']);
$Query = "UPDATE table SET html_entitied_column = '" . $updatedValue . "' ";
$Query .= "WHERE row_id = " . $row['row_id'];
mysql_query($Query, $connection);
}
This is simplified, no error handling etc.
Not sure what the processing time would be on millions of rows so you might need to break it up into chunks to avoid script timeouts.
I had the exact same problem. Since I had multiple clients running the application in production, I wanted to avoid running a PHP script to clean the database for every one of them.
I came up with a solution that is far from perfect, but does the job painlessly.
Track all the spots in your code where you use htmlentities() before inserting data, and remove that.
Change your "display data as HTML" method to something like this :
return html_entity_decode(htmlentities($chaine, ENT_NOQUOTES), ENT_NOQUOTES);
The undo-redo process is kind of ridiculous, but it does the job. And your database will slowly clean itself everytime users update the incorrect data.