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();
I am trying to be lazy (or smart): I have 7 checkboxes which correlate with 7 columns in a MySQL table.
The checkboxes are posted in an array:
$can = $_POST['can'];
I've created the following loop to dump the variables for the MySQL insert:
for($i=1;$i<8;$i++){
if($can[$i] == "on"){
${"jto_can".$i} = 'Y';
}
else{
${"jto_can".$i} = 'N';
}
}
print_r($jto_can1.$jto_can2.$jto_can3.$jto_can4.$jto_can5.$jto_can6.$jto_can7);
This correctly outputs:
YYNYYYY
However, when I attempt to use those variables in my MySQL update, it doesn't accept the changes.
mysqli_query($db, "UPDATE jto SET jto_can1 = '$jto_can1', jto_can2 = '$jto_can2', jto_can3 = '$jto_can3', jto_can4 = '$jto_can4', jto_can5 = '$jto_can5', jto_can6 = '$jto_can6', jto_can7 = '$jto_can7' WHERE jto_id = '$id'")or die(mysqli_error($db));
Can anyone explain why the print_r displays the variables whereas MySQL update does not?
Stick with the array, and form the query dynamically:
$sql = 'UPDATE jto SET ';
$cols = array();
foreach( range( 1, 7) as $i) {
$value = $_POST['can'][$i] == 'on' ? 'Y' : 'N'; // Error check here, $_POST['can'] might not exist or be an array
$cols[] = 'jto_can' . $i . ' = "' . $value . '"';
}
$sql .= implode( ', ', $cols) . ' WHERE jto_id = "' . $id . '"';
Now do a var_dump( $sql); to see your new SQL statement.
this is not a mysql problem. mysql will only see what you put into that string. e.g. dump out the query string BEFORE you do mysql_query. I'm guessing you're doing this query somewhere else and have run into scoping problems. And yes, this is lazy. No it's not "smart". you're just making MORE work for yourself. What's wrong with doing
INSERT ... VALUES jto_can1=$can[0], jto_can2=$can[1], etc...
When I run the following MySQL query via PHP and all of the elements of $_GET() are empty strings, all the records in the volunteers table are returned (for obvious reasons).
$first = $_GET['FirstName'];
$last = $_GET['LastName'];
$middle = $_GET['MI'];
$query = "SELECT * FROM volunteers WHERE 0=0";
if ($first){
$query .= " AND first like '$first%'";
}
if ($middle){
$query .= " AND mi like '$middle%'";
}
if ($last){
$query .= " AND last like '$last%'";
}
$result = mysql_query($query);
What is the most elegant way of allowing empty parameters to be sent to this script with the result being that an empty $result is returned?
my solution:
$input = Array(
'FirstName' => 'first',
'LastName' => 'last',
'MI' => 'mi'
);
$where = Array();
foreach($input as $key => $column) {
$value = trim(mysql_escape_string($_GET[$key]));
if($value) $where[] = "`$column` like '$value%'";
}
if(count($where)) {
$query = "SELECT * FROM volunteers WHERE ".join(" AND ", $where);
$result = mysql_query($query);
}
There's no point in running a (potentially) expensive query if there's nothing for that query to do. So instead of trying to come up with an alternate query to prevent no-terms being searched, just don't run the search at all if there's no terms:
$where = '';
... add clauses ...
if ($where !== '') {
$sql = "SELECT ... WHERE $where";
... do query ...
} else {
die("You didn't enter any search terms");
}
With your current code, if everything is empty, you will get the WHERE 0=0 SQL which is TRUE for all rows in the table.
All you have to do is remove the if statements...
EDIT:
Thank you so much for your answers, you really amaze me with so much wisdom :)
I am trying to relay on TuteC's code a bit changed, but can't figure how to make it work properly:
$valor = $_POST['valor'];
$post_vars = array('iphone3g1', 'iphone3g2', 'nome', 'iphone41', 'postal', 'apelido');
foreach($post_vars as $var) {
$$var = "'" . mysql_real_escape_string($_POST[$var]). "', ";
}
$sql = "INSERT INTO clientes (iphone3g1, iphone3g2, nome, iphone41, postal, apelido, valor) VALUES ($$var '$valor')";
$query= mysql_query($sql);
I know there's a bit of cheating on the code, i would need to use substring so the $$var wouldn't output a "," at the end where i need the values, instead i tried to insert a variable that is a value ($valor = $_POST['valor'];)
What is going wrong?
And for the others who tried to help me, thank you very much, i am learning so much with you here at stackoverflow.
I have a form with several field values, when trying to write a php file that reads those values it came out a mostruosity:
$codigounico= md5(uniqid(rand()));
$modelo=$_POST['selectName'];
$serial=$_POST['serial'];
$nif=$_POST['nif'];
$iphone3g1=$_POST['iphone3g1'];
$iphone3g2=$_POST['iphone3g2'];
$iphone3g3=$_POST['iphone3g3'];
$iphone3g4=$_POST['iphone3g4'];
$iphone3gs1=$_POST['iphone3gs1'];
$iphone3gs2=$_POST['iphone3gs2'];
$iphone3gs3=$_POST['iphone3gs3'];
$iphone3gs4=$_POST['iphone3gs4'];
$iphone41=$_POST['iphone41'];
$iphone42=$_POST['iphone42'];
$iphone43=$_POST['iphone43'];
$iphone44=$_POST['iphone44'];
$total=$_POST['total'];
$valor=$_POST['valor'];
$nome=$_POST['nome'];
$apelido=$_POST['apelido'];
$postal=$_POST['postal'];
$morada=$_POST['morada'];
$notas=$_POST['notas'];
$sql="INSERT INTO clientes (postal, morada, nome, apelido, name, serial, iphone3g1, iphone3g2, iphone3g3, iphone3g4, total, valor, iphone3gs1, iphone3gs2, iphone3gs3, iphone3gs4, iphone41, iphone42, iphone43, iphone44, nif, codigounico, Notas)VALUES('$postal', '$morada', '$nome', '$apelido', '$modelo', '$serial', '$iphone3g1', '$iphone3g2', '$iphone3g3', '$iphone3g4', '$total', '$valor', '$iphone3gs1', '$iphone3gs2', '$iphone3gs3', '$iphone3gs4', '$iphone41', '$iphone42', '$iphone43', '$iphone44', '$nif', '$codigounico', '$notas')";
$result=mysql_query($sql);
This is a very dificult code to maintain,
can I make my life easier?
To restrict which POST variables you "import", you can do something like:
$post_vars = array('iphone3g1', 'iphone3g2', '...');
foreach($post_vars as $var) {
$$var = mysql_real_escape_string($_POST[$var]);
}
EDIT: Changed addslashes by mysql_real_escape_string (thanks #Czechnology).
The issue I see is repetition of the same names four times over. This is how I would reduce it to two occurrences (you could drop it to one with more finagling).
$sql = 'INSERT INTO clientes (postal, morada, nome, apelido, name, serial, iphone3g1, iphone3g2, iphone3g3, iphone3g4, total, valor, iphone3gs1, iphone3gs2, iphone3gs3, iphone3gs4, iphone41, iphone42, iphone43, iphone44, nif, codigounico, Notas) VALUES(:postal, :morada, :nome, :apelido, :modelo, :serial, :iphone3g1, :iphone3g2, :iphone3g3, :iphone3g4, :total, :valor, :iphone3gs1, :iphone3gs2, :iphone3gs3, :iphone3gs4, :iphone41, :iphone42, :iphone43, :iphone44, :nif, :codigounico, :notas)';
preg_match_all('/:(\w+)/', $sql, $inputKeys);
$tokens = $inputKeys[0];
$values = array_map($inputKeys[1], function($k){
return mysql_real_escape_string($_POST[$k]);
});
$sql = str_replace($tokens, $values, $sql);
$result = mysql_query($sql);
Depending on how you want to separate your logic, a reversed approach might be more useful, where you would specify the array of key names and iterate over that to generate the SQL string.
<?php
$inputKeys = array('postal', 'morada', 'nome', 'apelido', 'name', 'serial', 'iphone3g1', 'iphone3g2', 'iphone3g3', 'iphone3g4', 'total', 'valor', 'iphone3gs1', 'iphone3gs2', 'iphone3gs3', 'iphone3gs4', 'iphone41', 'iphone42', 'iphone43', 'iphone44', 'nif', 'codigounico', 'Notas');
$keyList = '(' . implode(',', $inputKeys) . ')';
$valueList = 'VALUES (';
foreach ($inputKeys as $k) {
$valueList .= mysql_real_escape_string($_POST[$k]);
$valueList .= ',';
}
$valueList = rtrim($valueList, ',');
$valueList .= ')';
$sql = 'INSERT INTO clientes '.$keyList.' '.$valueList;
$result = mysql_query($sql);
This approach drops the occurrences of the keys to one and will probably more naturally with your application.
TuteC had a good aim but failed in details.
It makes me wonder, why noone has a ready made solution, but had to devise it on-the-fly. Nobody faced the same problem before?
And why most people trying to solve only part of the problem, getting variables only.
The goal is not to get variables.
The goal is to get a query. So, get yourself a query.
//quite handy way to define an array, saves you from typing zillion quotes
$fields = explode(" ","postal morada nome apelido name serial iphone3g1 iphone3g2 iphone3g3 iphone3g4 total valor iphone3gs1 iphone3gs2 iphone3gs3 iphone3gs4 iphone41 iphone42 iphone43 iphone44 nif codigounico Notas");
$sql = "INSERT INTO clientes SET ";
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$sql.= "`$field`='".mysql_real_escape_string($_POST[$field])."', ";
}
}
$sql = substr($set, 0, -2);
This code will create you a query without boring repeating the same field name many times.
But that's still not all improvements you can make.
A really neat thing is called a function.
function dbSet($fields) {
$set = '';
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$set.="`$field`='".mysql_real_escape_string($_POST[$field])."', ";
}
}
return substr($set, 0, -2);
}
put this function into your code library being included into all your scripts (you have one, don't you?)
and then use it for both insert and update queries:
$_POST['codigounico'] = md5(uniqid(rand()));//a little hack to add custom field(s)
if ($action=="update") {
$id = intval($_POST['id']);
$sql = "UPDATE $table SET ".dbSet($fields)." WHERE id = $id";
}
if ($action=="insert") {
$sql = "INSERT $table SET ".dbSet($fields);
}
So, your code become extremely short and reliable and even reusable.
The only thing you have to change to handle another table is $fields array.
It seems your database is not well planned as it contains seemingly repetitive fields (iphone*). You have to normalize your database.
The same approach to use with prepared statements can be found in this my question: Insert/update helper function using PDO
You could use a rather ugly part of PHP called variable variables, but it is generally considered a poor coding practice. You could include your database escaping at the same time. The code would look something like:
foreach($_POST as $key => $value){
$$key = mysql_real_escape_string($value);
}
The variable variables manual section says they do not work with superglobals like $_PATH, but I think it may work in this case. I am not somewhere where I can test right now.
PHP: extract
Be careful though and make sure you clean the data before using it.
$set = array();
$keys = array('forename', 'surname', 'email');
foreach($keys as $val) {
$safe_value = mysqli_escape_string($db, $_POST[$val]);
array_push($set, "$val='$safe_value'");
}
$set_query = implode(',', $set);
Then make your MySQL query something like UPDATE table SET $set_query WHERE... or INSERT INTO table SET $set_query.
If you need to validate, trim, etc, do it before the above code like this:
$_POST["surname"] = trim($_POST["surname"];
Actually, you could make your life easier by making your code a bit more complicated - escape the input before inserting into the database!
$sql =
"INSERT INTO clientes SET
"postal = '" . mysql_real_escape_string($_POST['postal']) . "', ".
"morada = '" . mysql_real_escape_string($_POST['morada']) . "', ".
...
First, I recommend you to create a key-value array like this:
$newClient = array(
'codigounico' => md5(uniqid(rand())),
'postal' => $_POST['postal'],
'modelo' => $_POST['selectName'],
...
);
In this array key is the column name your MySQL table.
In the code you've provided not every field is copied right from POST array (some are calculated, and some keys of the POST aren't equal with the tables column names), so you should use a flexible method.
You should still specify all columns and values but only once so code is still maintainable and you won't have any security errors if someone sends you a broken POST. As for me it looks more like configuration than coding.
Then I recommend you to write a function similar to this:
function buildInsertQuery($tableName, $keyValue) {
$result = '';
if (!empty($keyValue)) {
$delimiter = ', ';
$columns = '';
$values = '';
foreach ($keyValue as $key => $value) {
$columns .= $key . $delimiter;
$values .= mysql_real_escape_string($value) . $delimiter;
}
$columns = substr($columns, 0, -length($delimiter));
$values = substr($values, 0, -length($delimiter));
$result = 'INSERT INTO `' . $tableName . '` (' . $columns . ') VALUES (' . $values . ')';
}
return $result;
}
And then you can simply build your query with just one function call:
$query = buildInsertQuery('clientes', $newClient);