I have a script that I want to cron scheduled. Its all fine and dandy when I tested in the browser, working as it should but when run from php cli (php cron.php), mysql_real_escape_string loses the value given.
Any idea why?
UPDATED with code and a connection made before mysql_real_escape_string (but still not working)
$dbh = new PDO("mysql:host=localhost;dbname=xxx", 'xxx', 'xxx');
foreach ($prosArr[$i] as $val => $key) {
$fieldsStr .= "`".trim($val). '` , ';
$fieldVal .= '"'.mysql_real_escape_string($key). '" , ';
}
Here is output print_r of $prosArr[$i] obtained straight from the same CLI script
Array
(
[ProductCode] => 10077
[BranchCode] => 100
[RetailPrice] => 499.0000
[PromotionPrice] => 0.0000
[FullPrice] => 499.0000
)
Do not use mysql_real_escape_string() with PDO. They are different libraries and have are not meant to be used with each other.
Use PDO::Quote or parametrized queries instead.
To use mysql_real_escape_string, you should connect to MySQL first.
On the documentation in the note section
A MySQL connection is required before using mysql_real_escape_string()
otherwise an error of level E_WARNING is generated, and FALSE is
returned. If link_identifier isn't defined, the last MySQL connection
is used.
EDIT: You should use the prepared statement and not mix mysql and PDO API
Related
Throughout some testings; a little question popped up. When I usually code database updates; I usually do this via callbacks which I code in PHP; to which I simply pass a given mysqli connection object as function argument. Executing all queries of for example three queries across the same single connection proved to be much faster than if closing and reopening a DB connection for each query of a given query sequence. This also works easily with SQL transactions, the connection can be passed along to callbacks without any issues.
My question is; can you also do this with prepared statement objects ? What I mean is, considering we successfully established a $conn object, representing the mysqli connection, is stuff like this legit? :
function select_users( $users_id, $stmt ) {
$sql = "SELECT username FROM users where ID = ?";
mysqli_stmt_prepare( $stmt, $sql );
mysqli_stmt_bind_param( $stmt, "i", $users_id );
mysqli_stmt_execute( $stmt );
return mysqli_stmt_get_result( $stmt );
}
function select_labels( $artist, $stmt ) {
$sql = "SELECT label FROM labels where artist = ?";
mysqli_stmt_prepare( $stmt, $sql );
mysqli_stmt_bind_param( $stmt, "s", $artist );
mysqli_stmt_execute( $stmt );
return mysqli_stmt_get_result( $stmt );
}
$stmt = mysqli_stmt_init( $conn );
$users = select_users( 1, $stmt );
$rappers = select_labels( "rapperxyz", $stmt );
or is it bad practice; and you should rather use:
$stmt_users = mysqli_stmt_init( $conn );
$stmt_rappers = mysqli_stmt_init( $conn );
$users = select_users( 1, $stmt_users );
$rappers = select_labels( "rapperxyz", $stmt_rappers );
During the testing; I noticed that the method by using a single statement object passed along callbacks works for server calls where I call like 4 not too complicated DB queries via the 4 according callbacks in a row.
When I however do a server call with like 10 different queries, sometimes (yes, only sometimes; for pretty much the same data used across the different executions; so this seems to be weird behavior to me) I get the error "Commands out of sync; you can't run this command now" and some other weird errors I've never experienced, like the amount of variables not matching the amount of parameters; although they prefectly do after checking them all. The only way to fix this I found after some research was indeed by using different statement objects for each callback. So, I just wondered; should you actually ALWAYS use ONE prepared statement object for ONE query, which you then may execute N times in a row?
Yes.
The "commands out of sync" error is because MySQL protocol is not like http. You can't send requests any time you want. There is state on the server-side (i.e. mysqld) that is expecting a certain sequence of requests. This is what's known as a stateful protocol.
Compare with a protocol like ftp. You can do an ls in an ftp client, but the list of files you get back depends on the current working directory. If you were sharing that ftp client connection among multiple functions in your app, you don't know that another function hasn't changed the working directory. So you can't be sure the file list you get from ls represents the directory you thought you were in.
In MySQL too, there's state on the server-side. You can only have one transaction open at a time. You can only have one query executing at a time. The MySQL client does not allow you to execute a new query where there are still rows to be fetched from an in-progress query. See Commands out of sync in the MySQL doc on common errors.
So if you pass your statement handle around to some callback functions, how can that function know it's safe to execute the statement?
IMO, the only safe way to use a statement is to use it immediately.
I have this issue here with my code, and cant find where the problem actually is, has anyone had similar issue?
<?php
include("db.php");
if(isset($_POST['submit']))
{
$name=$_POST['namename'];
$job=$_POST['job'];
$message=$_POST['message'];
$insert=mysql_query("insert into commenttable(name,job,message)values('$name','$job','$message')")or die(mysql_error());
header("Location:../home.php");
}
?>
this is running on localhost
Server type: MySQL
Server version: 5.5.42 - Source distribution
forgot to mention that if I post simple comment such a "Hello" it works fine, but when i try to post comment like this
<INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');">
for a attack it wont work and I get the error message.
Im doing this for small attack project, this is why i need to get this to work.
Thanks!
If your code fails when you are trying to insert the text <INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');"> then obviously, what is happening is what Uueerdo suggested in his comment: the single quote right before "XSS" is interpreted by MySQL as the closing single quote of the string, leaving you with a dangling XSS');', which is, of course, a syntax error.
There are two ways to overcome this problem:
Programmatically escape the single quotes. This would be quite tricky if you were to do it by yourself, but there ought to be some library function in PHP for that, so it would look like message = escape_for_sql( message ). (Sorry I am not reproducing the dollar signs, I am allergic.)
Better yet, use a parameterized query, where you construct your query using a "?" in place of each value, signifying a parameter to the query, then you supply the value for each parameter, and then you execute the query. I don't know how this is done in PHP, search for "parameterized query PHP".
To extend #Mike's answer, the correct prepared-statement PHP syntax would be, using the mysql driver:
None. Don't use the mysql driver. It's been deprecated since forever.
Using mysqli:
// You need to define the following $db_* vars elsewhere
$dbh = new mysqli($db_host, $db_user, $db_password, $db_name;)
$query = "INSERT INTO commenttable (name, job, message) VALUES (?, ?, ?)";
$stmt = $dbh->prepare($query);
$stmt->bind_param($name, $job, $message);
$stmt->execute();
// When you're finished...
$stmt->close();
Using PDO:
// Edit the connection string as appropriate for your installation
$dbh = new PDO('mysql:host=mydbhost;dbname=whatever', $db_user, $db_password);
$query = "INSERT INTO commenttable (name, job, message) VALUES (:name, :job, :message)";
$stmt = $dbh->prepare($query);
$params = array(':name' => $name, ':job' => $job, ':message' => $message);
$stmt->execute($params);
// PDO has no explicit close() call.
I leave error handling as an exercise for the reader. Hope that helps.
I'm developing a system to manage in a very simple way some tables in the database.
The system first loads with Ajax the databases the user can see and manage. Then load the tables in that database and then load the data for that table.
I have something like this:
$.ajax({
url : "myUrl.php",
data : {
db : $dbSelector.val(),
table : tableToLoad
},
success : function (json) { /* Some cool stuff here */ }
});
And I've found you cannot use parameterized queries when the parameters are the db name, tables or columns, so I cannot do:
<?php
$query = "SELECT * FROM :db.:table";
$st = $pdo->prepare($query);
$st->execute(
array(
"db"=>$db,
"table" => $table
)
);
$rows = $st->fetchAll(PDO::FETCH_OBJ);
I cannot use mysql_ or mysqli_ filtering cause we don't have it installed.
You can use:
$db = substr($dbh->quote($db), 1, -1);
or just remove all non-alphanumeric characters with:
$db = preg_replace('/\W/', '', $db);
Accepted answer, as well as manual comment it refers to, is a fatal mistake.
PDO::quote has nothing to do with identifiers and shouldn't be used with them at all.
Removing quotes from its output makes it actually WIDE OPEN to SQL injection.
The very point of ingenious PDO::quote() function is to produce a correct string literal. Which means to quote a string and to escape the very quotes inside, if any. Unlike mysql_real_escape_string which does only partial formatting, this is the only proper way of handling strings.
And depriving this function from one of its duties will actually result in a plain injection.
PDO::quote() should never be used to format identifiers. They require totally different formatting.
I am using perl dbi connection to pull data remotely. I am looking to compress the data if possible.
Is there a way to do a file compression over the net with perl dbi for mysql?
Here is my snippet for getting data:
my $sth = $dbh->prepare("SELECT UUID(), '$node', 1, 2, 3, 4, vts FROM $tblist");
$sth->execute();
while (my($uid, $hostnm,$1,$2,$3,$upd,$vts) = $sth->fetchrow_array() ) {
print $gzip_fh "rec^A$uid^Ehost^A$hostnm^E1^A$1^E2^A$2^E3^A$3^E4^A$upd^Evts^A$vts^D";
}
$sth->finish;
Best option will be to use prepared statements; with this, once you have compiled the statement once you just have to send the arguments over the wire each time you need to run the queries.
The example here shows how to perform a simple prepare, if you are going to utilize the same query over and over again you should keep your $sth which you can continue to call $sth->execute() on with new variables. The reason this cuts down on your network traversal is because you're not sending the query each time you run $sth->execute($var), instead you're just passing an ID for the prepared statement and the variables that go into the ? placeholders.
$sth = $dbh->prepare("select * from table where column=?");
$sth->execute($var);
I am trying to run simple perl dbi example script to connect to mysql database and do some inserts.
Code:
#! bin/usr/perl -w
use strict;
use warnings;
use DBI();
my $dbh = DBI->connect(
"DBI:mysql:database=SPM;host=IP Address", "username", "password",
{'RaiseError'=>1}
);
my $dbh->do(
'INSERT INTO payment_methods(name, description)VALUES(CASH, DOLLAR)'
);
my $dbh->disconnect();
But when I try to run this using perl filename.pl I get following
Can't call method "do" on an undefined value at perldbi.pl line 12
That is where I have used do for first time.
I have tried to google it and also to tried all different kinds of forum but in vain, if you have any idea as to why this is happening and what is way around for this than it would be really great and I would really appreciate your help.
You have an extra my:
my $dbh->do(
'INSERT INTO payment_methods(name, description)VALUES(CASH, DOLLAR)'
);
Get rid of that my.
You either do not really have warnings enabled in your script or you are ignoring the warnings:
#!/usr/bin/perl
use strict;
use warnings;
my $x = 1;
my $x = 2;
C:\Temp> t
"my" variable $x masks earlier declaration in same scope at ...
I doubt it's the reason for the error message, but the values in the insert are probably not right:
VALUES(CASH, DOLLAR)
Should probably be:
VALUES(\'CASH\', \'DOLLAR\')
The \ is required because you're using a ' style string. If you use a " style string instead, you could leave out the \:
"... VALUES('CASH','DOLLAR')"
As daotoad said, your DBI->connect call is failing. Check your connection settings, see if you can connect to the database from the command line, etc. In your Perl script, always check the return value of DBI->connect() to see if the connection was successful.
my $dbh = DBI->connect("DBI:mysql:database=SPM;host=IP Address",...)
or die sprintf( 'connect() failed. Error: %s', DBI->errstr);
my $dbh->do(q{
INSERT INTO payment_methods(name, description)VALUES(CASH, DOLLAR)
});
...
Your database connection is failing. So $dbh is undefined.
Update: Both comments are right. Sinan has the correct answer--the OP is using my on every line.