How to get raw BSON from MongoDB with PHP "mongodb" extension - php

I am trying to get a binary BSON string from mongodb using PHP but I can't figure out how to get the document as BSON. It always parses it to a PHP object first.
I've tried to set a typeMap on the cursor but all this does is pass the already parsed PHP object to a bsonSerialize($object) function in the class.
The code looks like this:
<?php
$db = new \MongoDB\Driver\Manager('mongodb://localhost/test');
$query = new \MongoDB\Driver\Query([]);
$cursor = $db->executeQuery("test.contacts", $query);
foreach($cursor as $document) {
// $document is already parsed to a PHP stdObject
}

In recent MongoDB versions (since 3.6) the documents are returned as part of the responses, and the entire response is serialized as BSON. Meaning, the driver, when it receives a response, has to BSON-deserialize the entire response, and then part of the response will be given to the application as a found document.
There isn't a moment when the driver has just the document alone serialized as BSON.
So, if you need to have an individual document serialized as BSON, you'd need to do that yourself.

Related

Compatibility between PHP SOAP and Python SOAP libraries

The Moodle LMS can be used to quiz students. One optional question type (Opaque) uses SOAP to request questions from a service ( code at https://goo.gl/iGDIiy ).
There is a working "question server" implemented in PHP using the WSDL defined at https://goo.gl/kESENq
The complication that I am running into is that the code in the question type expected some return values to be a string. The response from the functioning test server looks like...
<SOAP-ENV:Body>
<ns1:getEngineInfoResponse>
<getEngineInfoReturn xsi:type="SOAP-ENC:string">
<engineinfo>
Note the xsi:type=..string. The data is actually returned as an XML formatted string by the PHP application:
/**
* A dummy implementation of the getEngineInfo method.
* #return string of XML.
*/
public function getEngineInfo() {
return '<engineinfo>
I'm trying to interface this to a Python+SOAP server. I've tried using both ZSI and Spyne. With ZSI, I used the WSDL provided with the sample server to generate the code stubs. The corresponding code simply returns a string much like the PHP code. The response from that is:
<ns1:getEngineInfoResponse>
<getEngineInfoReturn>
<engineinfo>
Note the lack of the string type modifier. This response gets received by the PHP code in Moodle as an object containing a single field with no name but containing the returned XML string. Because it's an object containing a string, rather than just a string, the code fails to parse the result correctly.
With Spyne, I get:
soap11env:Body>
<tns:getEngineInfoResponse>
<tns:getEngineInfoReturn><engineinfo>
from this code:
#srpc(_returns=String, _body_style='wrapped',
_out_variable_name="getEngineInfoReturn"
)
def getEngineInfo():
resp = "<engineinfo>\n"
This also returns an object with a single element (now named getEngineInfoReturn) that contains the appropriate string.
However, the receiver (which was happy with the WSDL produced)
still expects a string and not an object containing a string.
I'd rather get the Spyne version working than the ZSI version because it's easier to use. I've used SOAP before, but am not certain if the PHP code is making an unwarranted assumption about the return format or if I should be able to torque Spyne into producing that format. From reading the source code for the decorator function, I don't think I can.
So, is this a poorly coded client or is the expected SOAP schema normal? How can I get Spyne (or ZIS) to produce something similar?
Pass _out_body_style='bare' to #rpc.

simplexml_load_string not parsing my XML string. Charset issue?

I'm using the following PHP code to read XML data from NOAA's tide reporting station API:
$rawxml = file_get_contents(
"http://opendap.co-ops.nos.noaa.gov/axis/webservices/activestations/"
."response.jsp?v=2&format=xml&Submit=Submit"
);
$rawxml = utf8_encode($rawxml);
$ob = simplexml_load_string($rawxml);
var_dump($ob);
Unfortunately, I end up with it displaying this:
object(SimpleXMLElement)#246 (0) { }
It looks to me like the XML is perfectly well-formed - why won't this parse? From looking at another question (Simplexml_load_string() fail to parse error) I got the idea that the header might be the problem - the http call does indeed return a charset value of "ISO-8859-1". But adding in the utf8_encode() call doesn't seem to do the trick.
What's especially confusing is that simplexml_load_string() doesn't actually fail - it returns a cheerful XML array, just with nothing in it!
You've been fooled (and had me fooled) by the oldest trick in the SimpleXML book: SimpleXML doesn't parse the whole document into a PHP object, it presents a PHP API to an internal structure. Functions like var_dump can't see this structure, so don't always give a useful idea of what's in the object.
The reason it looks "empty" is that it is listing the children of the root element which are in the default namespace - but there aren't any, they're all in the "soapenv:" namespace.
To access namespaced elements, you need to use the children() method, passing in the full namespace name (recommended) or its local prefix (simpler, but could be broken by changes in the way the file is generated the other end). To switch back to the "default namespace", use ->children(null).
So you could get the ID attribute of the first stationV2 element like this (live demo):
// Define constant for the namespace names, rather than relying on the prefix the remote service uses remaining stable
define('NS_SOAP', 'http://schemas.xmlsoap.org/soap/envelope/');
// Download the XML
$rawxml = file_get_contents("http://opendap.co-ops.nos.noaa.gov/axis/webservices/activestations/response.jsp?v=2&format=xml&Submit=Submit");
// Parse it
$ob = simplexml_load_string($rawxml);
// Use it!
echo $ob->children(NS_SOAP)->Body->children(null)->ActiveStationsV2->stationsV2->stationV2[0]['ID'];
I've written some debugging functions to use with SimpleXML which should be much less misleading than var_dump etc. Here's a live demo with your code and simplexml_dump.

Cannot parse JSON with huge value

In my JSON I have 4 root values. 3 of them are parsed just good. The 4th dict is not even in the result. In this dict there is a UTF-8 string with key "base64" which length is 50915 symbols.
This happens only on the server (PHP 5.3.*), on my local (PHP 5.4.4) all works fine. What the hell is going on? Is there a limit on one object size?
Code
$json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
$result = $json->decode($var);
I think you should use json_decode instead.
As far as I know, the PEAR library to handle JSON was build because there were no proper way to handle JSON before PHP 5.1. I think you can leave this library aside and use json_* function instead.

Insert JSON into MongoDb directly from PHP

I have an Android application which sends json data to PHP script.
The PHP script have to save the data into MongoDB.
When I insert the data, MongoDB treat this data as a string.
$conn = new Mongo('mongodb://127.0.0.1:27017');
// access database
$db = $conn->Data;
// access collection
$collection = $db->Collection;
$collection->insert($myjson)
How can I say to MongoDB PHP driver that it is already a json document?
Thanks
The PHP MongDB Driver accepts arrays for inserts and queries (see here: http://www.php.net/manual/en/mongo.queries.php)
So you need to convert your JSON to an array.
Luckily, in general this is quite easy ... here is a snippet from a longer piece of code (see this article) to insert JSON data from the Twitter API into an array, then into MongoDB:
// Convert JSON to a PHP array
$usertimeline = json_decode($usertimeline);
// Loop array and create seperate documents for each tweet
foreach ($usertimeline as $id => $item) {
$collection->insert($item);
}
Note the json_decode() function can convert to an array by passing true as the second parameter.
Here's a tip for others who want to do this, but want to update records rather than insert new ones. In order to get Justin's approach to work, I had to make sure that I convert the _id object for each item to a MongoId:
// Convert JSON to a PHP array
$usertimeline = json_decode($usertimeline);
// Loop array and create seperate documents for each tweet
foreach ($usertimeline as $id => $item) {
$mongo_id = new MongoId($id);
$item->_id = $mongo_id;
$collection->update(array('_id' => $mongo_id), $item);
}
MongoDB uses BSON not JSON so you need to re-encode anyways. Also, I remember talking to kchodorow about this and the raw interface was not exposed then (been half a year at least) and I doubt it is now so even if you manage to get BSON data from somewhere , you can't avoid the de/encode.
As MongoDB PHP library supports conversion from JSON to BSON and BSON to PHP Std Class Object, You can follow simple steps.
//Convert Row (Document) to json
$json_row = json_encode($row);
//Convert JSON to BSON
$bson = \MongoDB\BSON\fromJSON($json_row);
//Convert BSON to PHP Std Class object
$row = \MongoDB\BSON\toPHP($bson);
// Insert Record to Document
$collection->insertOne($row);
You can get full MongoDB database backup and restore script from here
https://github.com/sulochanatutorials/php-mongodb-backup-restore
UPDATE 2021 WITH PHP 7 DRIVER:
Lets say your json string is
$myjson = {"name":"foo", "age":30}
First decode it with PHP json_decode. Which returns an array.
$myarraydata = json_decode($myjson)
Now you can directly insert it into mongoDB
$bulk = new MongoDB\Driver\BulkWrite(['ordered' => true]);
$bulk->insert($myarraydata);
$writeConcern = new MongoDB\Driver\WriteConcern(MongoDB\Driver\WriteConcern::MAJORITY, 1000);
$result = $connection->executeBulkWrite('dbname.collection_name', $bulk, $writeConcern);
Check bulk operation official documentation here.

Push JSON Encoded Data To Website in what format?

I need to push some JSON data to my website which I would like to read in PHP. What type of file should I make this? A PHP file with the JSON inside of a variable? I understand how to make a text file with JSON encoded data in it, but how do I get this into PHP? Should I use a PHP include with the JSON-encoded data in it assigned to a variable? Or should I read the file from PHP and put the contents into a variable?
Save your json string as plain text, then you can use:
$file = yourfile
$data = file_get_contents($file);
$parsed = json_decode($data);
// compacted:
$parsed = json_decode(file_get_contents($file));
See file_get_contents() and json_decode().
The advantage of doing this (versus storing it in a PHP file then including it) is that now any program or language that understands JSON can read the file.
The question is too vague for a definite "do this" answer, but here are some options and what they might be most suitable for:
Turn the json data into a PHP data structure. If this is a one-time thing (meaning you won't be getting a new json file every day or week or hour), then reading a file (file_get_contents) and parsing JSON (json_decode) for every request is a pretty big waste of resources since that data isn't changing on a regular basis. Just turn JSON key/value objects into PHP associative arrays, JSON strings into PHP strings, etc.
Just serve the json file. If this is data that will just wind up going to the client to be used in javascript anyway, there's no need to do anything special with it on the server, just parse the json on the client.
Put it in a database. This may be a little heavy-handed, but if you really need it in PHP and not just the client, and it is going to be changing or growing on a regular basis, it may be worth it to have something that handles this use case appropriately.

Categories