Can anybody help me to insert blob data in Mysql using MDB2 through php ?
I want to insert file into database using MDB2.
MBD2 setup is works fine.
This may help, as I had trouble with this for anyone in the future, note the quote sets the 'blob' type when sprintf injected each string generated by the quote functions. The key part appears to be using "file://" with a reference to a file for it to work this way.
$database is a mdb2 object as typically given in other examples online.
// NOTE BELOW: The quote function or lower layers - requires the file reference as below
// I could not pass the raw bytes through that were in a variable for some reason, as the
// quote method appeared to modify the bytes - maybe as it assumes a charset?
$sql = 'UPDATE %s SET %s=%s WHERE iconid=%d';
$sql = sprintf ($sql,
$database->quoteIdentifier('chanicon'),
$database->quoteIdentifier('icondata'),
$database->quote("file://".$_FILES['userfile']['tmp_name'][0], 'blob'),
$database->quote($_REQUEST['iconid'], 'integer')
);
Related
I want to write an image received via http into my database using PHP. I access the image with
$inputImage = file_get_contents('php://input');
Echoing the $inputImage works fine, so the transport to the server doesn't seam to be a problem.
I now tried to insert the image with
$sqlRequest="INSERT INTO Image(time, data) SET (NOW(), '$inputImage')";
mysqli_query($connection, $sqlRequest) or die("Error in Inserting " . mysqli_error($connection));
But it doesn't work and i recieve the following error
Error in Inserting 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 'SET (NOW(), '����' at line 1
Can someone give me a hint
thanks
edit:
okay changed the sytax problem, got to look for the blob problem
Use VALUES() instead of SET(). SET is meant for updating (using UPDATE) whereas VALUES() is meant for inserting (using INSERT).
See this for INSERT syntax and this for UPDATE syntax.
Looking at the funny characters ����, this sounds like you're trying to upload a binary file into a column that isn't capable of handling that type.
Sidenote edit: seeing your comment now, you still need to escape that variable.
By "escape", I mean that you need to use mysqli_real_escape_string().
If this isn't set, then you will need to ALTER your column to either be a BLOB or LONGBLOB.
More importantly, you need to escape the contents of $inputImage because that will be binary data and could contain bytes that will cause MYSQL to assume it is shorter than it actually is.
$inputImage = mysqli_real_escape_string($connection, $inputImage);
$sqlRequest="INSERT INTO Image(time, data) VALUES (NOW(), '$inputImage')";
And of course as I already stated in comments under your question, you're using the wrong syntax in your query.
Use VALUES() and not SET().
Add or die(mysqli_error($connection)) to mysqli_query() also.
Reference:
http://php.net/manual/en/mysqli.real-escape-string.php
Using a prepared statement would also work:
http://www.php.net/manual/en/mysqli.quickstart.prepared-statements.php
you want to make sure no data obstructing your sql string is stored so do this:
$inputImage = base64_encode(file_get_contents('php://input'));
before storing the data and then
$myImage = base64_decode( myGetImageFromDBFunction( $myImageID ) );
I have a mysql table that is connected to xcode via php, Im trying to update a cell using this code, and is returning nothing in the table.
<?php
$conn = mysql_connect($host, $user, $pass);
#mysql_select_db($db) or die("Unable to find database");
$routeID = $_GET["routeID"];
$newComment = $_GET["newComment"];
$query = "UPDATE routes SET comment = '$newComment' WHERE routeID='$routeID'";
mysql_query($query) or die (mysql_error("error"));
mysql_close();
?>
If I changed $routeID to routeID='routeID' or routeID=routeID it would update the entire comment column and add the actual id into it e.g. test?routeID=1
If I changed $routeID to routeID=1 or 20 etc. it would update the correct row. Any ideas on whats wrong with this.
It appears that your querystring is currently newComment=test?routeID=1, whereas it should be newComment=test&routeID=1.*
Consequently, PHP parses the current querystring as a single name newComment with the value test?routeID=1 rather than two names newComment and routeID with values test and 1 respectively.
However, please note that you absolutely must not simply concatenate values from the querystring directly into your SQL: so doing can lead to bugs if the values are not what was expected, which can be exploited by attackers to compromise your database. See How can I prevent SQL injection in PHP?
Please also note that, as documented under mysql_connect():
Warning
This extension is deprecated as of PHP 5.5.0, and will be removed in the future. Instead, the MySQLi or PDO_MySQL extension should be used. See also MySQL: choosing an API guide and related FAQ for more information. Alternatives to this function include:
mysqli_connect()
PDO::__construct()
Finally, please note that the (optional) argument to mysql_error() is the MySQL link identifier resource, $conn in your case: passing a string literal such as "error" will result in its failure.
* As documented under Data Handling, the default value for arg_separator.input (which is described as "List of separator(s) used by PHP to parse input URLs into variables.") is "&". This is consistent with the encoding used by browsers to submit form data, signified by the application/x-www-form-urlencoded MIME type.
I stored an image in a PostgreSQL database with column type bytea using PHP. The problem is every time I try to load the image in a browser it does not appear. The Firefox developer console says the image is either truncated or corrupt.
The PHP code:
//code for inserting into the database
if(array_key_exists('submit_pic', $_POST)){
$user=$_SESSION['name'];
if(isset($_FILES['thumbnail'])&&$_FILES['thumbnail']['size']>0){
$fi = $_FILES['thumbnail']['tmp_name'];
$p=fopen($fi,'r');
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
$q="update userinfo set image='{$dat}' where email='$user'";
$e=pg_query($q)or die(pg_last_error());
// code for retreving from database
require_once('conn.php');
session_start();
$user=$_SESSION['name'];
pg_query('SET bytea_output = "escape";');
$lquery ="select image from userinfo where email='$user'";
$lq = pg_query($lquery)or die(pg_last_error());
$lqq=pg_fetch_row($lq,'image');
header("conent-type:image");
echo pg_unescape_bytea($lqq[0]);
and i need to store the uploaded image in a database- i am actually using heroku thanks
TL;DR:
Delete addslashes($data). It's redundant here.
Double-escaping .. twice
$data=fread($p,filesize($fi));
$data=addslashes($data);
$dat= pg_escape_bytea($data);
You read the data in, escape it as if it were a string literal, then convert it to bytea octal or hex escapes. It could never work that way around even if pg_escape_bytea was sane, which it isn't.
PHP's pg_escape_bytea appears to double-escape the output so it can be inserted into a string literal. This is incredibly ugly, but there doesn't appear to be an alternative that doesn't do this double-escaping, so you can't seem to use parameterised statements for bytea in PHP. You should still do so for everything else.
In this case, simply removing the addslashes line for the data read in from the file is sufficient.
Test case showing that pg_escape_bytea double-escapes (and always uses the old, inefficient octal escapes, too):
<?php
# oh-the-horror.php
print pg_escape_bytea("Blah binary\x00\x01\x02\x03\x04 blah");
?>
Run:
php oh-the-horror.php
Result:
Blah binary\\000\\001\\002\\003\\004 blah
See the doubled backslashes? That's because it's assuming you're going to interpolate it into SQL as a string, which is extremely memory inefficient, ugly, and a very bad habit. You don't seem to get any alternative, though.
Among other things this means that:
pg_unescape_bytea(pg_escape_bytea("\x01\x02\x03"));
... produces the wrong result, since pg_unescape_bytea is not actually the reverse of pg_escape_bytea. It also makes it impossible to feed the output of pg_escape_bytea into pg_query_params as a parameter, you have to interpolate it in.
Decoding
If you're using a modern PostgreSQL, it probably sets bytea_output to hex by default. That means that if I write my data to a bytea field then fetch it back, it'll look something like this:
craig=> CREATE TABLE byteademo(x bytea);
CREATE TABLE
craig=> INSERT INTO byteademo(x) VALUES ('Blah binary\\000\\001\\002\\003\\004 blah');
INSERT 0 1
craig=> SELECT * FROM byteademo ;
x
----------------------------------------------------------------------------
\x426c61682062696e6172795c3030305c3030315c3030325c3030335c30303420626c6168
(1 row)
"Um, what", you might say? It's fine, it's just PostgreSQL's slightly more compact hex representation of bytea. pg_unescape_bytea will handle it fine and produce the same raw bytes as output ... if you have a modern PHP and libpq. On older versions you'll get garbage and will need to set bytea_output to escape for pg_unescape_bytea to handle it.
What you should do instead
Use PDO.
It has sane(ish) support for bytea.
$sth = $pdo->prepare('INSERT INTO mytable(somecol, byteacol) VALUES (:somecol, :byteacol)');
$sth->bindParam(':somecol', 'bork bork bork');
$sth->bindParam(':byteacol', $thebytes, PDO::PARAM_LOB);
$sth->execute();
See:
PHP: Large Objects, which has an example of exactly what you want;
PDOStatement::bindParam
how to store serialized object with namespace in database using pdo php
Bind BYTEA to PGSQL PDO Prepared Statement in PHP5
You may also want to look in to PostgreSQL's lob (large object) support, which provides a streaming, seekable interface that's still fully transactional.
Now, on to my soap box
If PHP had a real distinction between "byte string" and "text string" types, you wouldn't even need pg_escape_bytea as the database driver could do it for you. None of this ugliness would be required. Unfortunately, there are no separate string and bytes types in PHP.
Please, use PDO with parameterised statements as much as possible.
Where you can't, at least use pg_query_params and parameterised statements. PHP's addslashes is not an alternative, it's inefficient, ugly, and doesn't understand database specific escaping rules. You still have to manually escape bytea if you're not using PDO for icky historical reasons, but everything else should go through parameterised statements.
For guidance on pg_query_params:
Bobby tables, PHP section.
The PHP manual on pg_query_params
It is better to use postgres large objects if you really have to store images in your database. In the userinfo table instead of the image itself store just a link to it as loid (large object id).
Insert an image into the database:
pg_query("begin"); // pg_lo functions need to be run in a transaction
$loid = pg_lo_import('full_path_and_file_name');
pg_query("update userinfo set loid=$loid where email='$user'");
pg_query("commit");
Retrieve an image from the database:
$rs = pg_query("select loid from userinfo where email='$user'");
$loid = pg_fetch_row($rs, 0)[0];
pg_query("begin");
$blob = pg_lo_open($loid, "r");
header("Content-type: image");
pg_lo_read_all($blob);
pg_lo_close($blob);
pg_query("commit");
The loid field is of type oid (of course you can name it as you want).
Consider using the lo type from the lo extension instead of using the oid type. Using lo gives you automatic "orphan removal", where deleting a row from a table will automatically remove the associated large object, so it's good for cases where a table row "owns" a large object.
Storing links to images is especially convenient in case you use one image more than one time. However, you should pay attention to delete unused images from your database (PHP function pg_lo_unlink()).
Large objects in postgres documentation.
PHP manual: pg_lo_import.
I found a strange way of getting this to work too without using PDO.
Use a text field in postgresql instead of bytea.
On insert, prep your data like this:
$imgdta = pg_escape_string(bin2hex($filedata));
Then when you want to display the file after your query, use:
echo pack("H*", $img["filedata"]);
I'm not going to pretend I get why, but this worked for me!
As the source of your data is a file in the file system so it seems to me efficient to find an inspiration here:
In your db create an auxiliary function, run as superuser:
create or replace function bytea_import(p_path text, p_result out bytea)
language plpgsql as $$
declare
l_oid oid;
begin
select lo_import(p_path) into l_oid;
select lo_get(l_oid) INTO p_result;
perform lo_unlink(l_oid);
end;$$
security definer;
In your php execute a query like:
#make sure that postgres will have access to the file
chmod($_FILES['thumbnail']['tmp_name'], 0644);
pg_query("update userinfo set image=(select bytea_import('".$_FILES['thumbnail']['tmp_name']."')) where email='$user'");
I'm new to PHP, but not programming. Have come from an ASP [classic] background. In brief, I'm using PHP 5.4, with FastCGI on IIS7 and SQL Server 2005 Express. I've learnt the fundamentals, and have spent quite some time looking into security.
I'm sanitising both GET and POST input data. My db connection strings are in a separate file placed outside the web root. I'm using PDO prepared statements [though I've heard query+quote perform faster] with named placeholders along with db stored procedures.
I'm trying to understand why I would need to use additional arguments within the bindParam function, particularly data type options "PDO::PARAM_STR, 12" [second argument in that example represent the data length right?].
What are the benefits of specifying the data type and length within the bindParam? Is it needed if I'm using stored procedures in which the data type and length is already specified? Also, I believe I need to use something like "PDO::PARAM_INPUT_OUTPUT" to return a value from a stored proc?
Thanks!
** EDIT **
For some reason, if I use the PDO::PARAM_STR argument, my stored procs don't seem to write data into the db. So I omitted that argument. Here's my code:
$sql1 = $conn->prepare("EXEC insert_platts :userAgent, :userIp, 1, :source");
$sql1->bindParam(':userAgent', $userAgent);
$sql1->bindParam(':userIp', $userIp);
$sql1->bindParam(':source', $source);
$sql1->execute();
Also, rather than returning the identity value from the stored proc, I'm using lastInsertId() instead:
$lastRow = $conn->lastInsertId();
print $lastRow;
No, data type and data length are not needed. I'm using mysql stored procs and the parameters are never typed values, all though I validate them of course. I guess that the reason is extra security and INOUT params. Quote:
To return an INOUT parameter from a stored procedure, use the bitwise
OR operator to set the PDO::PARAM_INPUT_OUTPUT
have you tried this?
$params = array(
':userAgent'=>$userAgent,
':userIp' => $userIp,
':source' => $source
);
$sql1 = $conn->prepare("EXEC insert_platts :userAgent, :userIp, 1, :source");
$sql1->execute($params);
About special characters: are you using correct encodings? I mean, the same encoding in the php app and the DB... sometimes is hard to work with one encoding in the scripts and other in the database.. and very often problems like that arise...
I have a database with a BLOB field (weeklyOccupancy). I am trying to access the data in PHP using:
$sqlCmd = 'select weeklyOccupancy from Occupancy order by startDate;';
$pdoStmt = $dbh->query($sqlCmd);
$pdoStmt->bindColumn(1, $lob, PDO::PARAM_LOB);
$pdoStmt->fetch(PDO::FETCH_BOUND);
foreach($pdoStmt as $row){
$weeklyData = stream_get_contents($lob);
....
}
However, stream_get_contents says that $lob is a string (named "Resource id #1) although I believe it should be a stream. I have seen this mentioned as a bug (http://www.php.net/manual/en/pdo.lobs.php#96311) but the workaround is not relevant for my application - in which the blob holds a bit string not an image to be displayed.
Any ideas how I can get the data out of a blob field in PHP? Thanks
Not all PDO drivers return a LOB as a file stream; mysql 5 is one example. You can try treating lob as a string after the bind.
Oops. There was an earlier error in my code. Problem gone.