Joe
Joe

Reputation: 124

Parsing a string to then post

I have data being posted from another service as a string: heading="firstname","lastname"&user_1382926="Mike",Smith"&user_1383059="Sonny","Williams"&user_1303EM000014="Mike","Jones"

I'm lost in parsing this and because the user_* could be anything, it's not consistant.

I tried:

$query  = explode('&', 'heading="firstname","lastname"&user_1382926="Mike",Smith"&user_1383059="Sonny","Williams"&user_1303EM000014="Mike","Jones"');
$params = array();

foreach( $query as $param ){
list($name, $value) = explode('=', $param);
echo $params[urldecode($name)][] = urldecode($value);
}

But it just gives me:

"firstname","lastname""Mike",Smith""Sonny","Williams""Mike","Jones"

I want to be able to post it to:

$firstname  = $_POST['firstname'];
$lastname   = $_POST['lastname']; 
$stmt = $mysqli->prepare("INSERT INTO usertest (firstname,lastname) VALUES (?,?)"); 
$stmt->bind_param('ss', $firstname, $lastname);
$stmt->execute(); 

How do I parse this in order to then properly post?

Upvotes: 4

Views: 92

Answers (4)

cacba
cacba

Reputation: 413

First your string seems to be missing a quote. See

  &user_1382926="Mike",Smith"

Second, using explode seems like a bad idea as you will explode & and = inside of the quoted fields.

The way that I would normally approach this is a state machine. Using a regex (see PHP - split String in Key/Value pairs) is much simpler.

The language you are trying to match appears to be:

  • Keys can be made up of 1 or more alphanumeric or underscore characters.
  • Values are a comma separated list of quoted strings
  • Keys and values are separated by an equal sign
  • Key value pairs are separated by an &

The regex to get the key value pairing is:

$regex = '/&?([^=]+)=([^&]+)/';
preg_match_all($regex, $header, $r);
$result = array_combine($r[1], $r[2]);

The first entry in $result will contain the key 'header' and the value '"firstname","lastname"'.

Now we just need to convert the values in result from a string to a list of strings.

foreach ($result as $key => $value) {
    $regex = '("[^"]+")';
    preg_match_all($regex, $value, $r);
    $result[$key] = $r;
}

This is missing some edge cases such as escaped quotes inside of the values but should work for most cases.

In your example it produces:

  Array
  (
    [heading] => Array
        (
            [0] => "firstname"
            [1] => "lastname"
        )

    [user_1382926] => Array
        (
            [0] => "Mike"
            [1] => "Smith"
        )

    [user_1383059] => Array
        (
            [0] => "Sonny"
            [1] => "Williams"
        )

    [user_1303EM000014] => Array
        (
            [0] => "Mike"
            [1] => "Jones"
        )
  )

Upvotes: 0

Deepsy
Deepsy

Reputation: 3800

Since the author wrote: "Yes, I want to post it to an external URL." and "Unfortunately I do not have control over it. That's part of the problem. " I guess your problem can be solved like this.

Warning: This isn't the best solution, it may work, but it will cause a overhead. Please try to explain better what exactly you want to archieve.

$url = 'user_1382926="Mike","Smith"&user_1383059="Sonny","Williams"&user_1303EM000014="Mike","Jones"';
    $query  = explode('&', str_replace('"', '', urldecode($url)));

    $params = array();

    foreach( $query as $param )
    {
        list($name, $value) = explode('=', $param);
        $q = explode(',', $value);
        $params[$name] = 'firstname=' . $q[0] . '&lastname=' . $q[1];
    }

    $url = 'http://domain.com/post.php';


    $ch = curl_init();

    foreach ( $params as $current )
    {
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_POST, 2);
        curl_setopt($ch,CURLOPT_POSTFIELDS, $current);

        $result = curl_exec($ch);
    }

    curl_close($ch);

Upvotes: 0

Lucas
Lucas

Reputation: 479

I hate answers like these, but do you have any control over the post to you? That data is a mess and doesn't conform to the standards at all.

It should look like this... as you know:

firstname=bob&lastname=smith&user=123654&heading=someheading&...

Now, even if you have multiple people coming in one post, thats ok too - as long as they are in order. That would look like...

firstname=bob&lastname=smith&firstname=william&lastname=jones

When you get data like that, you can parse it like:

foreach($_POST['firstname'] as $k => $v){
     echo "Key: ".$k;
     echo " Value: ".$v;
}

would print Key: firstname Value:bob Key: firstname Value: william

Upvotes: 0

Samuel Cook
Samuel Cook

Reputation: 16828

Very rough, but this is the outcome that I arrived at:

$names = array();
$string = 'heading="firstname","lastname"&user_1382926="Mike","Smith"&user_1383059="Sonny","Williams"&user_1303EM000014="Mike","Jones"';

$arr = explode("&",$string);

foreach($arr as $key_values){
    if(substr($key_values,0,5) == 'user_'){
        $piecies = explode("=",$key_values);
        foreach($piecies as $key=>$val){
            if($key%2==0){
                continue;
            }
            preg_match_all('/"(.*?)","(.*?)"/',$val,$first_last_name);
            $names[] = array('firstname'=>$first_last_name[1],'lastname'=>$first_last_name[2]);
        }
    }
}

echo '<pre>',print_r($names),'</pre>';

foreach($names as $name){
    $firstname  = $name['firstname'];
    $lastname   = $name['lastname']; 
    $stmt = $mysqli->prepare("INSERT INTO usertest (firstname,lastname) VALUES (?,?)"); 
    $stmt->bind_param('ss', $firstname, $lastname);
    $stmt->execute(); 
}

Note: I added a double quote before Smith ("Mike","Smith") in your original string, as I was hoping it was just missing from the OP.

Upvotes: 1

Related Questions