So I have this PHP code to create a table. It should create a table called test101_list1, but instead it creates a table called 'test101'_'list1'. Without the backslash, PDO will see it as :username_ instead of :username. Also, I'd like to get rid of the quotes around the username and list name, but I still want to sanitize the input, as it uses user input. How can I do this?
$stmt = $db->prepare("CREATE TABLE `lists`.`:username\_:listname` ( `id` INT(10) NOT NULL AUTO_INCREMENT , `lang1` TEXT NOT NULL , `lang2` TEXT NOT NULL , PRIMARY KEY (`id`)) ENGINE = InnoDB CHARSET=utf8 COLLATE utf8_general_ci;");
$stmt->bindParam(':username', $username);
$stmt->bindParam(':listname', $listname);
$username = "test101";
$listname = "list1";
$stmt->execute();
I have the below code which works fine and updates each record contained in the array:
$check_list = isset($_POST['check_list']) ? $_POST['check_list'] : array();
foreach($check_list as $check_list) {
$query = "UPDATE `stock` SET `signature_id` = 0,
user_id = 0,
`status_id` = 1
WHERE `id` = '$check_list'";
$result = mysqli_query($conn, $query);
I now need it to execute multiple queries for each result in the array so I have changed the code to the following using mysqli_multi_query:
$check_list = isset($_POST['check_list']) ? $_POST['check_list'] : array();
foreach($check_list as $check_list) {
$query = "UPDATE `stock` SET `signature_id` = 0,
user_id = 0,
`status_id` = 1
WHERE `id` = '$check_list';
INSERT INTO `returned`
(`id`, `stock_id`, `signature_id`,
`user_id`, `timestamp`)
VALUES ('','$check_list','$id',
'$user_id',now())";
$result = mysqli_multi_query($conn, $query);
But it now only executes one UPDATE and one INSERT for the first record in the array, and ignores the others
#RiggsFolly is giving the best advice about prepared parameterised statements and transactions due to re-usability and security, but if you want/need to stay with mysqli_multi_query, (because you don't want to transition to a new querying process mid-project or because it is otherwise unappealing to you) here is how mysqli_multi_query can serve you:
Query Combination:
If the SET values stay the same and only the id's are different, all UPDATE queries can be merged into a single query. If the values are static you can use implode(), if not you can chose between using a (verbose/ugly) CASE statement in the SET clause of a single query, or create multiple UPDATE queries as in your original post.
$queries="UPDATE `stock` SET `signature_id`=0,`user_id`=0,`status_id`=1 WHERE `id` IN (".implode(',',$check_list).");";
Likewise with the INSERT queries, they can all be merged into one statement with implode() or a foreach loop that only extends the VALUE portion.
$queries.="INSERT INTO `returned` (`stock_id`,`signature_id`,`user_id`,`timestamp`) VALUES ('".implode("','$id','$user_id',now()),('",$check_list)."','$id','$user_id',now());";
or
$queries.="INSERT INTO `returned` (`stock_id`,`signature_id`,`user_id`,`timestamp`) VALUES ";
foreach($check_list as $k=>$check_list){
// manipulate $id and $user_id as needed
$queries.=($k==0?"":",")."('$check_list','$id','$user_id',now())";
}
Failure Awareness:
If you don't need any kind of indication of success then a one-liner will do (keep this outside of any loops of course):
mysqli_multi_query($conn,$queries)
otherwise, you'll need a slightly larger block of code:
if(mysqli_multi_query($conn,$queries)){
do{
echo "<br>Rows = ",mysqli_affected_rows($conn);
} while(mysqli_more_results($conn) && mysqli_next_result($conn));
}
if($mysqli_error=mysqli_error($conn)){
echo "<br>Syntax Error: $mysqli_error";
}
I have tested my solution using implode() for both queries and was successful using:
$check_list=array(1,3,5,6,10,11);
and a database setup of:
CREATE TABLE `stock` (
id int(10) NOT NULL AUTO_INCREMENT,
signature_id int(10) NOT NULL,
user_id int(10) NOT NULL,
status_id int(10) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE `returned` (
id int(10) NOT NULL AUTO_INCREMENT,
stock_id int(10) NOT NULL,
signature_id int(10) NOT NULL,
user_id int(10) NOT NULL,
`timestamp` datetime NOT NULL,
PRIMARY KEY (id)
);
/* Declaring your `id` columns with AUTO_INCREMENT means you can omit them from your INSERT query. */
/* Depending on your mysql version, creating a default datetime for `timestamp` may be possible which then would permit omitting `timestamp` from your INSERT query too. */
INSERT INTO `stock` (`signature_id`,`user_id`,`status_id`) VALUES
(1,1,1),
(2,2,2),
(3,3,3),
(4,4,4),
(5,5,5),
(6,6,6),
(7,7,7),
(8,8,8),
(9,9,9),
(10,10,10),
(11,11,11),
(12,12,12);
The built query looks like this:
UPDATE `stock` SET `signature_id`=0,`user_id`=0,`status_id`=1 WHERE `id` IN (1,3,5,6,10,11);INSERT INTO `returned` (`stock_id`,`signature_id`,`user_id`,`timestamp`) VALUES ('1','','',now()),('3','','',now()),('5','','',now()),('6','','',now()),('10','','',now()),('11','','',now());
I want to be able to create dynamic tables, for custom user surveys... like survey monkey... how would I go about create something like that?
Because I want to give the ability to the user to create the survey, with different amount of text fields, and different a option fields... I would need to create a custom table for each survey.
Would something like this be possible?
<?php
$table_name = 'survey_'.$_POST['surveyid'];
$query = 'CREATE TABLE ? (
`responseid` INT NOT NULL AUTO_INCREMENT,
`textarea1` TEXT NULL,
`textarea2` TEXT NULL,
`textarea3` VARCHAR(255) NULL,
`drop_down1` VARCHAR(255) NULL,
`drop_down2` VARCHAR(255) NULL,
`bool1` BIT NULL,
`bool2` BIT NULL,
PRIMARY KEY (`responseid`))';
if($stmt = $mysqli->prepare($query)){
$stmt->bind_param('s', $table_name);
$stmt->execute();
$stmt->close();
}else die("Failed to prepare");
?>
The above example comes back with "Failed to prepare", because I don't think I can prepare a table name... is there another work around using mysqli?
if(ctype_digit($_POST['surveyid']) && $_POST['surveyid']>0){
$table_name = 'survey_'.$_POST['surveyid'];
$query = 'CREATE TABLE '.$table_name.' (
`responseid` INT NOT NULL AUTO_INCREMENT,
`textarea1` TEXT NULL,
`textarea2` TEXT NULL,
`textarea3` VARCHAR(255) NULL,
`drop_down1` VARCHAR(255) NULL,
`drop_down2` VARCHAR(255) NULL,
`bool1` BIT NULL,
`bool2` BIT NULL,
PRIMARY KEY (`responseid`))';
I know I can just try to sanitize the $_POST['surveyid'] (like I did above) but I prefer to prepare it if possible.
$table_name = 'survey_'.$_POST['surveyid'];
Do not do the above. It is easy for a hacker to exploit your site if you include $_GET or $_POST data directly in any SQL string.
But you can't use parameters for a table name. A parameter takes the place of a single scalar value only. You can prepare CREATE TABLE but you can't use parameters for identifiers (e.g. table names).
The best practice is to make sure your table name conforms to a rule, for example only the leading portion of a string of numeric digits, up to the maximum length of a MySQL table name:
$table_name = 'survey_' . strspn(trim($_POST['surveyid']), '0123456789', 0, 56);
If you have other rules for a surveyid, then you could use preg_replace():
$table_name = 'survey_' . preg_replace('^(\w+)', '$1', trim($_POST['surveyid']));
It is not possible to prepare a data definition language statement like "CREATE TABLE". I can't find the reference in the MySQL docs that explains this, but I did find a good explanation on the PHP documentation site.
Hi! My table structure looks like this:
CREATE TABLE IF NOT EXISTS `search` (
`key` varchar(255) NOT NULL,
`id` int(15) NOT NULL auto_increment,
UNIQUE KEY `key` (`key`),
KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
And this is how I try to add data into my table:
$stmt = $mysqli->prepare("INSERT INTO search(key) VALUES (?)");
$stmt->bind_param('s',$keyword);
$stmt->execute();
$stmt->close();
This is what I got:
Call to a member function bind_param() on a non-object
But it works when I do this:
$stmt = $mysqli->prepare("INSERT INTO search VALUES (?,NULL)");
$stmt->bind_param('s',$keyword);
$stmt->execute();
$stmt->close();
Is there any other way besides putting NULL to the VALUES?
is there any necessity that i should put NULL to auto increments?
No.
And there is no necessity in finding an answer by means of wild guess either.
You have to get the error message instead.
For which purpose always have this line right before connecting to mysqli:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
speaking for the certain query, key is a mysql keyword and have to be quoted in backticks
INSERT INTO search(`key`) VALUES (?)
I am trying to dynamically insert 'NULL' into the database using PDO.
TABLE STRUCTURE:
CREATE TABLE IF NOT EXISTS `Fixes` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'PK',
`CurrencyId` int(11) NOT NULL COMMENT 'FK',
`MetalId` int(11) NOT NULL COMMENT 'FK',
`FixAM` decimal(10,5) NOT NULL,
`FixPM` decimal(10,5) DEFAULT NULL,
`TimeStamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `CurrencyId` (`CurrencyId`),
KEY `MetalId` (`MetalId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=13 ;
PHP / PDO QUERY:
$sql = 'UPDATE
Fixes
SET
FixAM = :fixAM,
FixPM = :fixPM
WHERE
MetalId IN (SELECT Id FROM Metals WHERE Name = :metal) AND
CurrencyId IN (SELECT Id FROM Currencies Where Id = :currency)';
$stmt = $db->prepare($sql);
for ($i = 0; $i<3; $i++) {
$stmt->execute(array(
':metal' => 'Silver',
':fixAM' => $fix['FixAM'][$i],
':fixPM' => $fix['FixPM'][$i],
':currency' => ($i+1))
);
}
e.g. sometimes, the value for $fix['FixPM'][$i] is sometimes 'NULL'. How do I insert this into the database? When I run the query and then view the data in the database, this record shows 0.0000, and not null.
How do I insert NULL values using PDO? provides a few solutions.
I dont think I can use $stmt->execute(array( ':v1' => null, ':v2' => ... )) as per example because sometimes the item is null, and sometimes not. As such, I need to refer to the variable I have created $fix['FixPM'][$i] and make that null as and when needed
Thanks in advance.
This appears to me to be a(n unreported?) bug in PDO's prepared statement emulation:
the implementation of PDOStatement::execute() eventually invokes pdo_parse_params();
that, in turn, attempts to quote/escape values based on the relevant parameter's data type (as indicated by the $data_type arguments to PDOStatement::bindValue() and PDOStatement::bindParam()—all parameters provided as $input_parameters to PDOStatement::execute() are treated as PDO::PARAM_STR, as stated in the documentation of that function);
string-typed values are escaped/quoted by calling the relevant database driver's quoter() method irrespective of whether they are null: in the case of PDO_MySQL, that's mysql_handle_quoter(), which (eventually) passes the value to either mysqlnd_cset_escape_quotes() or mysql_cset_escape_slashes(), depending on the server's NO_BACKSLASH_ESCAPES SQL mode;
given a null argument, both of those functions return an empty string.
My opinion is that, prior to switching on the parameter's type (in step 2 above), pdo_parse_params() should set the type to PDO::PARAM_NULL if the value is null. However, some might argue that this would prevent type-specific handling of null values where appropriate, in which case the string case (in step 3 above) should definitely handle null values before proceeding with a call to the driver's quoter() method.
As an interim workaround, disabling prepared statement emulation is usually for the best anyway:
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);