I have started using MongoDB for one of my PHP project. In that database, i am trying to use MongoDB sharding concept. I got the below link and tried,
MongoDB Sharding Example
It is working well. But the problem is, in the above example, everything is done in command prompt. But i am trying to do everything in PHP. I am not able to get any example in PHP.
So far, i have started with these piece of codes,
$connection = new Mongo();
$db = $connection->selectDB('TestDB');
$db = $connection->TestDB;
$connection->selectDB('admin')->command(array('addshard'=>'host:port'));
$connection->selectDB('admin')->command(array('enablesharding'=>'TestDB'));
$connection->selectDB('admin')->command(array('shardcollection'=>'TestDB.large', 'key' => '_id'));
It is not working. Also, i dont know how to set shard servers and config database in PHP.
Is there any other way to do MongoDB sharding in PHP?
MongoDB's database commands are case-sensitive. You were passing in lowercase command names, while the real commands are camelCased (see: sharding commands). Additionally, the key paremeter of shardCollection needs to be an object.
A corrected version of your above code would look like:
$connection->selectDB('admin')->command(array('addShard'=>'host:port'));
$connection->selectDB('admin')->command(array('enableSharding'=>'TestDB'));
$connection->selectDB('admin')->command(array('shardCollection'=>'TestDB.large', 'key' => array('_id' => 1)));
Additionally, you should have been able to examine the command result of to determine why this wasn't working. The ok field would be zero, and an errmsg field would explain the error (e.g. "no such cmd: addshard").
Lastly, if you're attempting to mimic the shell's functionality to configure sharding in PHP, you may realize that some of the shell methods are more than just database commands. For any of those methods, you can get the JS source by omitting the parentheses. For example:
> sh.addTagRange
function ( ns, min, max, tag ) {
var config = db.getSisterDB( "config" );
config.tags.update( {_id: { ns : ns , min : min } } ,
{_id: { ns : ns , min : min }, ns : ns , min : min , max : max , tag : tag } ,
true );
sh._checkLastError( config );
}
That would be a useful hint for what an addTagRange() function in PHP would need to do.
Related
Konfiguration
Ubuntu 14.04
PHP 5.5.9
MongoDB 3.0.2
MongoDB PHP driver 1.6.6
Setup
I have a globally distributed MongoDB replica set (for testing purpose) with 3 servers. One has priority = 1, others have priority = 0 so they will never become primary.
This setup is used to distribute files to the replicated servers by adding them directly on the primary server using GridFS. Distribution works fine.
I have created a simple php watcher script which is executed on the secondary servers using read preference \MongoClient::RP_NEAREST. I wanted to determine the timestamp when the replicated received all files from the primary.
I wanted to make sure that the php script on the secondary servers are using the mongodb instance on their server (and not the primary), and therefore I stopped the primary mongodb server. After doing this, the two servers are keeping their secondary role.
Issue
If the primary server is unavailable, I was still able to execute queries like count() and find() on regular collections (also fs.files collection).
But calls that use GridFS will throw an MongoConnectionException: No candidate servers found exception.
Script
I have created a little script with which you should be able to reproduce the error.
$serverList = '...';
$conn = new \MongoClient(
'mongodb://'.$serverList,
array(
'replicaSet' => 'r0',
'readPreference' => \MongoClient::RP_NEAREST,
'username' => 'bat',
'password' => '',
'db' => 'bat'
)
);
$db = $conn->selectDB('bat');
echo 'works fine...';
$files = $db->selectCollection('fs.files');
$documentsCount = $files->count();
$documents = $files->find();
foreach($documents as $document) {
echo $document['filename'] . ', ';
}
echo 'throws exception...';
$gridfs = $db->getGridFS();
$documentsCount = $gridfs->find()->count();
$documents = $gridfs->find();
foreach($documents as $document) {
echo $document->getFilename();
}
If the primary server is unavailable, the lines after echo 'works fine...'; will work fine, while the line after echo 'throws exception...'; will throw an exception.
Maybe this is related to an issue in the java driver JAVA-401, there was a similar problem with usage of secondary servers and gridfs. Maybe the gridfs ist trying to ensuring indices if the fs.files collection contains less than 1000 files which is not possible on secondary.
I figured out the problem, it was simply the incorrect line $gridfs->find()->count(). If you execute $gridfs->count() or $gridfs->find() it works fine.
So you'll have to use $gridfs->count() instead of $gridfs->find()->count().
I dont't know why $gridfs->find()->count() works correctly (and only correctly) if a primary server is available.
I'm trying to understand a strange behavior using PHP with mongodb 2.4.3 win32.
I try to have server side generated sequence ids.
When inserting documents using a stored function as one of the parameters it seems that the stored function is called several times at each insertion.
Let's say I have a counter initialized like this:
db.counters.insert( { _id: "uqid", seq: NumberLong(0) } );
I have a stored function named getUqid which is defined as
db.system.js.save(
{ _id: "getUqid",
value: function () {
var ret = db.counters.findAndModify(
{ query: { _id: "uqid" },
update: { $inc: { seq: NumberLong(1) } },
new: true
} );
return ret.seq;
}
} );
When I do three insertions like this:
$conn->test->ads->insert(['qid' => new MongoCode('getUqid()') , 'name' => "Sarah C."]);
I get something like that:
db.ads.find()
{ "_id" : ObjectId("51a34f8bf0774cac03000000"), "qid" : 17, "name" : "Sarah C." }
{ "_id" : ObjectId("51a34f8bf0774cac03000001"), "qid" : 20, "name" : "Michel D." }
{ "_id" : ObjectId("51a34f8bf0774cac03000002"), "qid" : 23, "name" : "Robert U." }
Any clue why qid is getting stepped by 3 ? It should mean that I received three call to my stored function right ?
Thanks in advance for your help, Regards.
PS: secondary question: are NumberLong still required to be sure we have 64bit unsigned integer in internal mongodb storage ? Any command to cross-check that in the shell ?
Cross-referencing this question with PHP-841. From the PHP side of things, you're actually storing a BSON code value in the qid field. You can likely verify that when fetching results back from the database or doing a database export with the mongodump command.
The issue is with the JS shell wrongfully evaluating the code type upon display, and that's the point where findAndModify is executed. This fix should be included in a subsequent server release.
In the meantime, Sammaye's suggestion to call findAndModify from PHP is the best option for this sort of functionality. Coincidentally, it is also what is done in Doctrine MongoDB ODM (see: IncrementGenerator). It does require an additional round trip to the server, but that is necessary since MongoDB has no facility for executing JS callbacks during a write operation.
If minimizing the round-trips to MongoDB is of utmost importance, you could insert the documents by executing server-side JS through PHP with MongoDB::execute() and do something like returning the generated ID(s) as the command response. Of course, that's generally not advisable and JS evaluation has its own caveats.
So I have a php script on a web server listening for mongoDB queries via a JSON object POST with another page building and sending queries to the php service. All my standard queries such as :
{"field1":"2342342","field2":"234234"} are sent and return the correct resutls.
However, when I try to send a query that includes a range of values it returns nothing.
{"field2":"1234","date" : {$gte : "2013-02-11"},"date" : {$lte : "2013-02-11"}}
I can go into the command line and call:
db.collection.find({"field2":"1234","date" : {$gte : "2013-02-11"},"date" : {$lte : "2013-02-11"}} )
which returns the results as expected. Obviously there is something going on that I do not fully understand.
PHP command doing the search:
$c_collection->find(json_decode($request));
Any help would be much appreciated.
You are attempting to search the database using a duplicate element name. MongoDb would issue an error such as this while performing this search:
Duplicate element name 'date'.
You need to place your range within the same block. For example:
{
'date': {
$gte:"datehere",
$lte:"datehere"
}
}
In PHP:
$criteria = array('date' => array('$gte' => 'datehere', '$lte' => 'datehere'));
Then use that json as your criteria.
Also, why are you decoding the criteria before passing it to the database? The method can accept an array just fine.
In Subversion 1.6, there was an .svn directory in every working copy directory. I could use the following code to quickly retrive the current revision number without the need for shell access/execution.
public function getSubversionRevision() {
if(file_exists("../.svn/entries")) {
$svn = File("../.svn/entries");
return (int)$svn[3];
}
return false;
}
Subversion 1.7 breaks this code. There is now only one .svn directory per local repository. There is an entries file in this directory but it no longer has anything useful for me. It looks like everything I need is now in a SQLite database. Specifically wc.db. I suppose I could use PHP's SQLite functions to get the info I need, but this sounds a little too expensive to run on every (or close to every) page load.
Any ideas? Breaking out the exec function and hoping that Subversion binaries are installed (and in the $PATH!) is a last resort. To summarize, I need to find a way to locate the .svn directory at the root of the repository (which could be different depending on your checkout location) and then somehow parse a file in there (probably wc.db) in a cost-effective way.
try using a SVN library SVN as it will give you access to repository information and more functionality over SVN repository.
Take a look at function svn_status you will receive and array of svn repository information
Array (
[0] => Array (
[path] => /home/bob/wc/sandwich.txt
[text_status] => 8 // item was modified
[repos_text_status] => 1 // no information available, use update
[prop_status] => 3 // no changes
[repos_prop_status] => 1 // no information available, use update
[name] => sandwich.txt
[url] => http://www.example.com/svnroot/deli/trunk/sandwich.txt
[repos] => http://www.example.com/svnroot/
[revision] => 123 // <-- Current Revision
//..
)
)
You can write a script to svn update for you every time, and scrap the revision number from the update's output into a file. The following bash script should more or less do it:
#!/bin/bash
svn --non-interactive update ..
svn --non-interactive update .. | perl -p -e "s/.* revision ([\d]*)\./\$1/" > ../version.phtml;
I implemented a clumsy (but relatively thorough) implementation of Subversion 1.7 revision retrieval in TheHostingTool. Check the commit message for an explanation. The function is contained in class_main.php which is one directory after /trunk (/trunk/includes/class_main.php). You'll need to adjust relative paths for your specific needs. This is a slightly modified version of the function found in class_main.php for use elsewhere.
public function getSubversionRevision() {
// This will work for Subverson 1.6 clients and below
if(file_exists("../.svn/entries")) {
$svn = File("../.svn/entries");
return (int)$svn[3];
}
// Check the previous directories recursively looking for wc.db (Subversion 1.7)
$searchDepth = 3; // Max search depth
// Do we have PDO? And do we have the SQLite PDO driver?
if(!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
$searchDepth = 0; // Don't even bother...
}
for($i = 1; $i <= $searchDepth; $i++) {
$dotdot .= '../';
if(!file_exists("$dotdot.svn/wc.db")) {
continue;
}
$wcdb = new PDO("sqlite:$dotdot.svn/wc.db");
$result = $wcdb->query('SELECT "revision" FROM "NODES" WHERE "repos_path" = "'.basename(realpath('..')).'"');
return (int)$result->fetchColumn();
}
if($this->canRun('exec')) {
exec('svnversion ' . realpath('..'), $out, $return);
// For this to work, svnversion must be in your PHP's PATH enviroment variable
if($return === 0 && $out[0] != "Unversioned directory") {
return (int)$out[0];
}
}
return false;
}
Instead of .= '../' you may want to use str_repeat if you don't start at 1. Or, you could simply define $dotdot ahead of time to wherever you would like to start.
Or just query:
SELECT "changed_revision" FROM "NODES" ORDER BY changed_revision DESC LIMIT 1;
if you wonder the last revision of the whole repo! :)
Excuse me, but if you want portable and bullet-proof solution, why not call Subversion CLI inside PHP?
You can use svn info inside any directory of WC (capture, parse output and get a set of data) of svnversion if you want to get only global revision
Using the AMI (API connection with an Asteriskserver so I can use a PHP Socket connection) I'm trying to catch the recieving data using PHP in a way that I can record outgoing and incomming calls for the CRM system (webbased) used at the company I work for.
But I'm not getting the result I am hoping for...
The full code can be found on PasteBin http://pastebin.com/AwRNBW2G
I catch the outgoing calls this way, and that works:
if($givenkey = array_search("Context: from-internal", $content)){
$calleridKey = $givenkey + 1;
$idSIP = $givenkey - 1;
$dialNumber = str_replace("Extension: 0","31",$content[$calleridKey]);
$dialNumber = str_replace("Extension: ", "", $dialNumber);
$fromSIP = str_replace("Channel: SIP/", "", $content[$idSIP]);
$fromSIP = substr($fromSIP, 0, 2);
$dialTime = date('r');
$uitgaand = array(
"Phonenumber" => $dialNumber,
"Type" => "Uitgaand",
"datetime" => $dialTime,
"SIP" => $fromSIP
);
The incomming calls are being catched this way, but that's not working properly:
if($givenkey = array_search("AppData: Using CallerID ", $content)){
if(array_search("Channel: SIP/31000000000", $content)+5 == $InCallKey = array_search("AppData: Using CallerID", $content)){
$calleridNum = explode('"',str_replace('AppData: Using CallerID "',"",$content[$InCallKey]));
$pickupSource = array_search("Source: SIP/31000000000", $content);
if($pickupSource+1 == $pickupKey = array_search("Destination: SIP/", $content)){
$pickupBy = str_replace("Destination: SIP/","",$content[$pickupkey]);
$pickupBy = substr($pickupBy, 0, 2);
$dialTime = date('r');
$inkomend = array(
"Phonenumber" => $calleridNum[0],
"Type" => "Binnenkomend",
"datetime" => $dialTime,
"SIP" => $pickupBy
);
I have the array that I make not available right now but, if necessary, I can save the array and post it here with personal data filtered.
I know that the code I'm using right now is not neat, but I wrote it with the goal: quick result. If I have a working code I will optimize it and clean it up. Tips about this are also very welcome. It's too bad that I cannot find any good documentation about this so I have to start from the beginning and could only find the working class that I'm using right now, however it's not very complete.
I had to write this part without any knowledge about VOIP or AMI or Asterisk.
To be short, here are my questions:
- How can I record incoming and outgoing calls to eventually save them in a database by using the AMI?
- How can I keep alive the connection with the server the best way? The method I'm using now is not optimal as the connection fails atleast once within 48 hours.
- Do you have tips or suggestions about optimizing the code and neater code-writing? And do you maybe know any functions that I could use instead of a function that I am using?
With regards,
Dempsey
Since recently I get this error which
I cannot solve properly. This error
creates itself after about 15 minutes
running. It would run atleast 24 hours
before:
PHP Notice: fwrite(): send of 16 bytes failed with errno=32 Broken pipe in /var/www/html/phpami/AMILoader.php on line 147
Net_AsteriskManagerException: Authorisation failed in /var/www/html/phpami/AMILoader.php on line 173
#0 /var/www/html/phpami/AMILoader.php(173): Net_AsteriskManager-login('GEBRUIKERSNAAM','WACHTWOORD')
#1 /var/www/html/phpami/AMILoader.php(306): Net_AsteriskManager-_sendCommand('Action: Ping???...')
#2 /var/www/html/phpami/AMILoader.php(543): Net_AsteriskManager->ping()
#3 {main}
Can anyone help me with this too? The
authorisation data is correct (it is
using the same data in the whole
script and it does get a connection).
Also I don't get the response 'Action:
Ping???...' which it says is being
send by the script as command, but
where do the three questionmarks and
periods come from?
this framework should be handy:
https://github.com/marcelog/PAMI
otherwise you can check vTiger sources and how it handles ami integration:
http://www.vtiger.com/index.php?Itemid=57&id=30&option=com_content&task=view
If your using php, one of the easiest way to connect to the AMI is using the php-astmanager class. It supports callback on certain "events" so that you can catch the data you need. The best (only?) maintained copy is part of FreePBX and can be pulled right out of the latest version (2.9 as of this writing).