PHP PDO MS Access how to read blob images?

2019-07-22 00:02发布

I have images as BLOB's in an MS ACCESS database. I have so far used them with odbc acces from PHP and it works fine. Here comes the simplified program:

code:
<?php
ini_set("odbc.defaultlrl", "5M");
$dbName = $_SERVER["DOCUMENT_ROOT"]."\\..\db\\teknofo.mdb";
$con = odbc_connect("Driver={Microsoft Access Driver (*.mdb)};Dbq=".$dbName,'','') or die('Ups');
ob_clean();
header('Content-Type: image/*');
$sql = "SELECT photo FROM Medlemmer WHERE Id=17";
$rd = odbc_exec($con, $sql);
if (odbc_fetch_row($rd)) { echo odbc_result($rd,"photo"); }
odbc_close($con);
ob_end_flush();
?>

I am in the process of converting to MySql but will have to use MS Access for some timg: Therefor I am making the new code using PDO, but I am not able to read the data correct.

Here comes the new

<?php
$dbName = $_SERVER["DOCUMENT_ROOT"]."\\..\db\\teknofo.mdb";
$con = new PDO("odbc:DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=$dbName; Uid=; Pwd=;");
$sql = "SELECT photo FROM Medlemmer WHERE id=?";
$st = $con->prepare($sql);
$st->execute(array(17));
$st->bindColumn('photo', $photo, PDO::PARAM_LOB);
$st->fetch(PDO::FETCH_BOUND);
odbc_longreadlen($st, 131072);        
odbc_binmode($st,ODBC_BINMODE_CONVERT);                            
ob_clean();
header('Content-Type: image/*');
if ($rd = $st->fetch(PDO::FETCH_BOUND)) {
echo $rd['photo'];
ob_end_flush();
$con = null;
?>

The last code Works fin with MySql (changed connection string) but not with MS Access.

I have searced the net for a long time but have not been able to find a solution.

Can anybody help pleasse?

I could use the first code, but I need to be able to handle BLOB's for other purposes as well.

3条回答
男人必须洒脱
2楼-- · 2019-07-22 00:49

Using the solution from Gord Thompson I ran into a bug. I don't know why the endings were messed up on some binaries but this is how I fixed it. Sort of a hack to patch an unknown corruption source but it worked.

// create array of character pairs (e.g.: '42', '4D', '7A', ...)
$photoArray = str_split($photoChars, 2);

// at this point some jpegs were ending in 'ff', '0D', '09'
// they should end in 'ff', 'D9'
$photo_end = sizeof($photoArray)-1;
if($photoArray[$photo_end] === '9'){
    $photoArray[$photo_end - 1] = 'D9'; // fix the previous element to be end of image
    unset($photoArray[$photo_end]); // remove the last element
}

// pack into binary string
//     ref: http://stackoverflow.com/a/5473057/2144390
$photoData = call_user_func_array("pack", array_merge(array("C*"), $photoArray));
查看更多
甜甜的少女心
3楼-- · 2019-07-22 00:52

PHP and the Access ODBC driver have never been the best of friends, and apparently that continues to be the case with PDO_ODBC and the Access ODBC driver. The two wrinkles here were

  1. The BLOB is returned as an ASCII string representing the hex values of the image data (e.g., '424D7AC000...'), and

  2. That string contains a spurious NULL character every 255 characters.

The code I managed to get working is:

<?php
$dbName = $_SERVER["DOCUMENT_ROOT"]."\\test.mdb";
$con = new PDO("odbc:DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=$dbName; Uid=; Pwd=;");
$sql = "SELECT Photo FROM Clients WHERE id=?";
$st = $con->prepare($sql);
$st->execute(array(1));
$st->bindColumn(1, $photoChars, PDO::PARAM_LOB);
$st->fetch(PDO::FETCH_BOUND);

// $photoChars is a long string of hex, e.g., '424D7A...'

// PDO+Access_ODBC apparently injects a NULL every 255 characters, 
//     so remove them first
$photoChars = str_replace("\0", "", $photoChars);

// create array of character pairs (e.g.: '42', '4D', '7A', ...)
$photoArray = str_split($photoChars, 2);

// convert to numeric values
for ($i = 0; $i < sizeof($photoArray); $i++) {
    $photoArray[$i] = hexdec($photoArray[$i]);
}

// pack into binary string
//     ref: http://stackoverflow.com/a/5473057/2144390
$photoData = call_user_func_array("pack", array_merge(array("C*"), $photoArray));

header('Content-Type: ' . image_type_to_mime_type(IMAGETYPE_PNG));
header('Content-Disposition: attachment; filename="untitled.bmp"');
echo $photoData;
查看更多
Bombasti
4楼-- · 2019-07-22 00:58

I know its an old thread, but i stumbled uppon the same problem and @gord-thompson's answer helped me. But I realized that there is a simpler and faster way to do it.

All you need to do is strip out the \0-Bytes and then invoke pack directly:

    // PDO+Access_ODBC apparently injects a NULL every 255 characters,
    //     so remove them first
    $photoChars = str_replace("\0", "", $photoChars);

    //Pack the HEX-String into a binary string and encode it with base64
    base64_encode(pack("H*", $photoChars));

So str_split, hexdec is not needed anymore. All you have to do is pack the HEX-Data that comes from PDO+Access into binary format.

查看更多
登录 后发表回答