1

I'm working with PostgreSQL's HSTORE data type and PHP.

I require the ability to transform PostgreSQL's returned hstore string into a PHP array. I've tried using the fromPg() method defined here as mentioned in [this post][2], however when I save the value and attempt to retrieve it, when I encounter a value similar to the following:

"myKey" => "my\"Value"

... the fromPg() method breaks the value into two array entries, the first having a key of "myKey" and a value of "my\" and the second having a key of "Value\"" and a blank value.

I'm wondering if anyone else has had this problem and if someone would be willing to provide a more functional method of transforming an hstore string into it's equivalent PHP array.

Here is a code sample to replicate the issue I'm having with the existing "solution":

<?php
function fromPg($data) {
    $split = preg_split('/[,\s]*"([^"]+)"[,\s]*|[,=>\s]+/', $data, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    $hstore = array();
    for($index = 0; $index < count($split); $index = $index + 2) {
        $hstore[$split[$index]] = $split[$index + 1] != 'NULL' ? $split[$index + 1] : null;
    }
    return $hstore;
}

$hstore_string = '"myKey" => "my\"Value"';
$hstore_array = fromPg($hstore_string);

print '<pre>';
print_r($hstore_array);
print '</pre>';

I've finally broken down and created a PHP library of my own specifically designed to tackle this problem, as well as many other shortcomings of PHP's PostgreSQL driver such as automatic detection and transformation of PostgreSQL Hstores, Arrays, Dates, Geometric data-types, etc. It's available on GitHub at: https://github.com/JDBurnZ/PHPG

1

3 Answers 3

2

If you're interpreting an hstore string that comes (directly or not) from user input, Piotr's solution is potentially dangerous (as all user-input evals). I cannot come up with a way to abuse it, but still I'd rather avoid eval'ing an unknown string.

Usage:

hstore(<some_array_or_object>, false) converts the input to a valid hStore string literal and returns it:

hstore(array('k1' => 'v1', 'k2' => 'v2')) => "k1"=>"v1","k2"=>"v2"

hstore(<some_array_or_object>) converts the input to a valid hStore, single-quoted, followed by ::hstore

hstore(array('k1' => 'v1', 'k2' => 'v2')) => '"k1"=>"v1","k2"=>"v2"'::hstore

hstore(<some_string>) converts from an hstore string (as it comes from a query) to array

hstore('"k1"=>"v1","k2"=>"v2"') => array('k1' => 'v1', 'k2' => 'v2')

It handles NULLs (both ways), and properly escapes/unescapes keys and values.

<?php

/**
 * mixed hstore(mixed $input[, bool $prepared = false])
 *      Convert from hstore string to array, or from array/object to hstore.
 * Inner arrays/objects are serialized but deserialization is up to you; you
 * are expected to keep track of which fields you sent as non-scalars.
 *
 * @param mixed $input          A string (from hstore) or an array/object
 * @param type $prepared        Array or object to convert to hstore string
 * @return mixed                Depends on the input
 */
function hStore($input, $prepared=true)
{
    if (is_string($input))
    {
        if ($input === 'NULL')
        {
            $output = NULL;
        }
        else
        {
            $re = '_("|^)(.*?[^\\\\"])"=>"(.*?[^\\\\"])("|$)_s';
            preg_match_all($re, $input, $pairs);
            $mid = $pairs ? array_combine($pairs[2], $pairs[3]) : array();

            foreach ($mid as $k => $v)
            {
                $output[trim($k, '"')] = stripslashes($v);
            }
        }
    }
    elseif (is_null($input))
    {
        $output = $prepared  ? 'NULL::hstore' : 'NULL';
    }
    elseif (!is_scalar($input))
    {
        foreach ((array)$input as $k => $v)
        {
            !is_scalar($v) && ($v = serialize($v));
            $entries[] = '"' . addslashes($k) . '"=>' .
                         '"' . addslashes($v) . '"';
        }

        $mid = empty($entries) ? '' : join(', ', $entries);

        $output = $prepared ? "'{$mid}'::hstore" : $mid;
    }

    return $output;
}

?>

This question is indeed a duplicate of Convert postgresql hstore to php array.

I'm just re-posting here my answer to that post.

Sign up to request clarification or add additional context in comments.

Comments

1

Try this:

function unescape_hstore($hstore)
{        
  $hstore = preg_replace('/([$])/', "\\\\$1", $hstore);
  $unescapedHStore = array();
  eval('$unescapedHStore = array(' . $hstore . ');');
  return $unescapedHStore;
}

And feed this function with output from postgresql.

Comments

0

You can use Pomm's converter system. It comes with a HSTore converter from/to PHP - Postgresql.

Hope it helps…

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.