MongoDB Plugin Design: Basic Components

 

UniServer 6-Carbo
MongoDB plugin design.

MongoDB

Basic Components

An application requires several components (functions and scripts) these need to tested before integration. Our Windows application for MogoDB is no exception.

This tutorial assume you have downloaded Uniform Server 6-Carbo and the MongoDB tutorial see previous page for details.

General

Single point references

Our final application will use single point references. A changeable parameter will have a unique location. It is changeable by any user (manually or script) when using this parameter it is assumed to have changed hence before using always read it afresh.

For example MongoDB configuration file is a single point of reference. It contains a parameter defining port to use. A user or script can change its value. Any script performing some action that uses the port will read its value directly from the configuration file before use.

Similarly another point of reference will be the Admin name/password file. Bear the above in mind even if the examples hard code parameters.

Batch file Command-line

Using a command line interface becomes very tedious. Most of what you enter for testing is reparations and prone to typing errors. My preference is to create a batch file containing the command-line to run. This also avoids creating shortcuts on the desktop.

:mode con:cols=65 lines=20
TITLE UNIFORM SERVER - Option
COLOR B0
@echo off
cls

===== command-line to run =====

:pause

EXIT

Basic batch file

  • :mode con:cols=65 lines=20 - To enable width and height Un-comment
  • TITLE - Change to whatever you like or delete line
  • COLOR - sets background colour
  • cls - clears any rubbish displayed
  • === === - Replace with command lines to run
  • :pause - Un-comment to pause
  • EXIT - Force exit generally not required

Top

Preparation

Create a new folder named a_test in folder UniServer\usr\local\mongo_tutorial

This will contain our test batch files and scripts.

Top

Command prompt

Lets start with a small script that opens a command prompt where Mongo binaries are located.

A user would typically create a short cut to this folder! Not very portable, an alternative is to open a command prompt manually at this location as follows:

  • Click start
  • Click run. Type in cmd to open a command window
  • Type cd (change directory) enter full path to the bin folder

We what to perform the same using a php script create a new file named run_cmd.php in folder a_test.

With the following content:

run_cmd.php:

<?php
print "Test\n";
?>

Double clicking on file run_cmd.php you will find it does not run! I have assumed PHP has not been installed on the PC hence there is no file association.

Note: If it does run you have PHP installed however that is not the version or configuration file we want to run.

All test scripts require PHP version and configuration file installed with Uniform Server 6-Carbo.

For testing we use a batch file to run PHP test scripts. Create a new file Run_cmd.bat in folder a_test with the following content:

Run_cmd.bat:

TITLE UNIFORM SERVER - Run cmd
COLOR B0
@echo off
cls

cd ..\..\php
php.exe -c mongo_tutorial_cli.ini ..\mongo_tutorial\a_test\run_cmd.php

pause

EXIT

  • cd ..\..\php
    • cd - Change directory
    • ..\..\php - Move up two-folder levels and down into folder PHP
  • -c mongo_tutorial_cli.ini - Informs PHP to use configuration file mongo_tutorial_cli.in
  • ..\mongo_tutorial\a_test\run_cmd.php - Informs PHP what script to run
    • Move up one folder level and down into folder a_test use file run_cmd.php

Note: This batch file is generic and will be renamed along with minor modification to run other test scripts.

Test:

Run run_cmd.php by double clicking on Run_cmd.bat you will see “Test” is printed in the window.

CLI Script

We want to create a function that opens a command prompt window. This window must remain open however our main application does not want to wait for it to be closed hence it must be detached from the main process.

Function needs to force current working directory to Mongo bin folder however it must reinstate original working. For flexibility we want to use absolute paths that are relative to folder UniServer. A slight contradiction path to folder UniServer is variable and dependent where a user located Uniform Server. All paths from folder UniServer are definable.

Top

Start a second command window

At this point we can’t script anything! How do you start a second command window?

Add the following line as show to our test batch file:


:mode con:cols=65 lines=20
TITLE UNIFORM SERVER - Run cmd
COLOR B0
@echo off
cls

cd ..\..\php
php.exe -c mongo_tutorial_cli.ini ..\mongo_tutorial\a_test\run_cmd.php

start "UNIFORM SERVER Mongo Command Line" cmd.exe /k "COLOR B0 && cls &&dir"

pause

EXIT

  • start – Informs the command processor we want to run an application in this case it is another comman window cmd.exe
  • "UNIFORM SERVER Mongo Command Line" – Title to be displayed in window. Note it contains space hence must be enclosed in quotes
  • cmd.exe – program to run
  • /k – Do not close window keep it open
  • "COLOR B0 && cls &&dir" – We want to run a series of commands in this window again because it contains spaces must be enclosed in quotes
    • COLOR B0 - Set background colour
    • cls - Clear screen
    • dir - List directory
  • Note each command is seperated by &&

Test:

Double click on Run_cmd.bat

You may have to drag top window away to reveal the first command window. Note the message “Press any key to continue” this indicates our new window is detached from the first.

You can delete that line from the batch file its no longer required. We are going to code it as a command string in the function.

Tip

I personally hate long lines in scripts. First thing I would perform is to add a back slash to all quotes as shown:

start \"UNIFORM SERVER Mongo Command Line\" cmd.exe /k \"COLOR B0 && cls &&dir\"

Slit that line into smaller manageable parts:

start 
\"UNIFORM SERVER Mongo Command Line\"
cmd.exe /k \"COLOR B0 && cls &&dir\"

Them rebuild the command line string as follows:

$cmd1 = "start  ";
$cmd2 = "\"UNIFORM SERVER Mongo Command Line\" ";
$cmd3 = "cmd.exe /k \"COLOR B0 && cls &&dir\"";
$cmd  = $cmd1.$cmd2.$cmd3;

It involves a little extra work however when it comes to debugging it is well worth the effort.

Top

Detached process

If the above command line is run using something like PHP exe format of function shown below

string exec (string $command [, array &$output [,int &$return_var ]])

For example

exec($cmd):

The script will hang until the second window is closed. This is because processes open are child processes of the script.

To run a detached process use the following:

pclose(popen($cmd,'r'));

For a detailed explanation see PHP CLI: Detached Processes

Top

Finished test script

<?php

chdir(dirname(__FILE__)); // Change wd to this files location

$path_array      = explode("\\usr",getcwd());              // Split
$mongo_base      = $path_array[0];                         // Path to UniServer 
$mongo_base_f    = preg_replace('/\\\/','/', $mongo_base); // Replace \ with /

//=== FOLDERS ===
define("MONGO_START", "$mongo_base_f/unicon/tray_menu_2");  // Mongo start
define("MONGO_BIN",   "$mongo_base_f/usr/local/mongo_tutorial/bin");// Binaries


open_cmd_window(); // Run our test function

//=== Open a command window ===================================================
// Opem a cmd window in bin folder 
function open_cmd_window(){
  $return_wd = getcwd();                    // Save current wd 
  chdir(MONGO_BIN);                         // Change wd to Mongo Bin

       $base = preg_replace('/\//','\\', MONGO_BIN); // Replace / with \
       $cmd1 = "start  ";
       $cmd2 = "\"UNIFORM SERVER Mongo Command Line\" ";
       $cmd3 = "cmd.exe /k \"COLOR B0 && cls &&dir\"";
       $cmd  = $cmd1.$cmd2.$cmd3;
       pclose(popen($cmd,'r'));             // Start a new process ignore output  
 
  chdir($return_wd);                        // Restore original wd
}
//=============================================== END Open a command window ===
?>
  • The current working directory is split at folder usr giving the absolute path up to and including folder UniServer.
  • PHP prefers forward slashes hence backward slashes are converted and new path stored in variable $mongo_base_f
  • I am thinking about the final application. hence folder constants are defined (MONGO_START and MONGO_BIN) these are destined for a separate include file.
  • In a similar vein have defined a function name run using open_cmd_window()


  • First operation of the function is to switch working directory to “bin” folder
  • Windows does really hate forward slashes hence the conversion.
  • The command line is assembled as explained.
  • This command is executed as a detached process
  • Finally original working directory is restored.

Top

Testing finished script

Comment out the pause in batch file to look like this:

TITLE UNIFORM SERVER - Run cmd
COLOR B0
@echo off
cls

cd ..\..\php
php.exe -c mongo_tutorial_cli.ini ..\mongo_tutorial\a_test\run_cmd.php

:pause

EXIT

Run this modified batch file.

After a short time batch file closes leaving a command window that can be used to run Mongo’s command-line tools.

Top

Summary

That completes one component (function) of our main application. Detail included was not intended to be patronising it was aimed at users new to CLI and DOS (cmd) batch file scripting.

Our main application will be click and run the above function with minor modification will run Mongo,s client interface directly covered in next section.

Top

Add structure

Looking at our first test script you will notice there is a structure already evolving. Defining paths will be a common task for all test scripts. Having access to common functions will also be a requirement. We don’t want to keep typing the same ting over and over again.

Include file

Solution to the above repetition is to place common elements and functions into an included file. After completing each test script we transfer appropriate elements to this file.

Create a new file mongo_db_inc.php with the following content:

<?php

$path_array      = explode("\\usr",getcwd());              // Split at folder usr
$mongo_base      = $path_array[0];                         // find drive letter and any sub-folders 
$mongo_base_f    = preg_replace('/\\\/','/', $mongo_base); // Replace \ with /

//=== FOLDERS ===
define("MONGO_BIN",   "$mongo_base_f/usr/local/mongo_tutorial/bin");  // Binaries for MongoDB

//=== FILES ===

//=== Open a command window ===================================================
// Opem a cmd window in bin folder 
function open_cmd_window(){
  $return_wd = getcwd();                    // Save current wd 
  chdir(MONGO_BIN);                         // Change wd to Mongo Bin

       $base = preg_replace('/\//','\\', MONGO_BIN); // Replace / with \
       $cmd1 = "start  ";
       $cmd2 = "\"UNIFORM SERVER Mongo Command Line\" ";
       $cmd3 = "cmd.exe /k \"COLOR B0 && cls &&dir\"";
       $cmd  = $cmd1.$cmd2.$cmd3;
       pclose(popen($cmd,'r'));             // Start a new process ignore output  
 
  chdir($return_wd);                        // Restore original wd
}
//=============================================== END Open a command window ===
?>

Our test script requires modification delete lines moved into the include file. Add an include line to read the file content into our test script. Modified file shown below:

<?php
chdir(dirname(__FILE__)); // Change wd to this files location
include_once "mongo_db_inc.php";
open_cmd_window(); // Run our test function
?>

Top

Add configuration files

From the previous page we know two configuration files are required create these in folder bin with the following content:

No-authentication:

config_no_auth.ini

Authentication

config_auth.ini

dbpath  = ../data/mongodb  # Path to db 
bind_ip = 127.0.0.1        # Localhost
port    = 27017            # Port to use 
noauth  = true             # use 'true' 
verbose = true 
dbpath  = ../data/mongodb  # Path to db 
bind_ip = 127.0.0.1        # Localhost
port    = 27017            # Port to use
verbose = true             # to disable, comment out.
auth    = true             #

We need to locate these files hence two constants are defined. Add the following two lines to the include file:

//=== FILES ===
define("CONFIG_NO_AUTH_F",   "$mongo_base_f/usr/local/mongo_tutorial/bin/config_no_auth.ini"); 
define("CONFIG_AUTH_F",      "$mongo_base_f/usr/local/mongo_tutorial/bin/config_auth.ini"); 

Top

Add name password file

For scripting we require access to the Admin name and password these are stored in file mongo_name_password create this file in folder bin with the following content

mongo_name_password

root:root

We need to locate this file hence a constant is defined. Add the following line to the include file:

define("NAME_PWD_F",         "$mongo_base_f/usr/local/mongo_tutorial/bin/mongo_name_password"); 

Top

Get and Set Mongo Port

Mongo port is a changeable parameter. Before using we need to read its value from a configuration file. In our final application we will provide a user with the option of changing it.

Four functions are required a pair (set-port and get-port) for no authentications and a matching pair for authentication.

Create a new batch file Run_port.bat with following content:

TITLE UNIFORM SERVER - Run cmd
COLOR B0
@echo off
cls

cd ..\..\php
php.exe -c mongo_tutorial_cli.ini ..\mongo_tutorial\a_test\run_port.php

pause

EXIT
  • This will run our new script run_port.php
  • pause - Prevents window closing allowing us to view any error message and test text we print to the screen.

New test script

Create a new test script run_port.php wth the following content:

<?php
chdir(dirname(__FILE__)); // Change wd to this files location
include_once "mongo_db_inc.php";

set_mongo_port_no_auth("12345");
$port = get_mongo_port_no_auth();
print "\n###$port####\n";

set_mongo_port_auth("56789");
$port = get_mongo_port_auth();
print "\n###$port####\n";

=== Delete this and replace with four functions shown below =====

?>
  • Set the port to any value for testing
  • The functions get the port from a correcponding configuration file
  • Port is printed to screen.
  • Port is enclosed between #, this test is checking for any additional spaces. Note really required since the digits are targeted with a regx.

Top

set_mongo_port_no_auth($new_port)

// === Set Mongo port No Auth =================================================
function set_mongo_port_no_auth($new_port){
 $new_line = "port    = ".$new_port."                 # Port to use\r\n";

 if ($filearray=file(CONFIG_NO_AUTH_F)) {             // read file into array
    foreach ($filearray as $txt) {                    // scan array for port
      if(preg_match("/^\s*port\s*=\s*(\d+)/", $txt)){ // test for match 
        $new_array[] = $new_line;                     // found add new line 
      }
      else{                                           // No match
        $new_array[] = $txt;                          // Save original line
      }
    }
 }
 $str = implode($new_array);                   // Convert array to string
 file_put_contents(CONFIG_NO_AUTH_F,$str);     // Save to file
}
// ============================================ END Set Mongo port No Auth ====
  • There are many ways to replace a string in a file.
  • This method matches a string and replaces the whole line.
  1. First define a line that includes the new port
  2. Read the file into an array
  3. Scan this array line-by-line and create a new array
  4. Look for a line that matches "port ddddn" on finding a match add new line to new array
  5. If a match is not found add original line to new array.
  6. On completion convert array to a string
  7. Write this string to the configuration file (file is overwritten)
  • Note: This code structure is very flexible and adaptable.

Top

get_mongo_port_no_auth()

// === Get Mongo port No Auth =================================================
function get_mongo_port_no_auth(){
  if ($filearray=file(CONFIG_NO_AUTH_F)) {   // read file into array
    foreach ($filearray as $txt) {           // scan array for port
 
      if(preg_match("/^\s*port\s*=\s*(\d+)/", $txt,$match)){ // test save $match 
       $mongo_port =  $match[1];             // match found save port number 
       break;                                // give up nothing else to do
      }
    }
  }
  else {                                     // failed to read file
    echo "Cannot read the file";
  }
  return $mongo_port;
}
// ============================================ END Get Mongo port No Auth ====
  • Hey! Have you seen this code before?
  • Yep! It’s a variant of the above.
  1. Read the file into an array
  2. Scan this array line-by-line
  3. Look for a line that matches "port ddddn" extract port number
  4. Return port number
  • Code can be reduced if you wish

Top

set_mongo_port_auth($new_port)

// === Set Mongo port Auth ====================================================
function set_mongo_port_auth($new_port){
 $new_line = "port    = ".$new_port."                 # Port to use\r\n";

 if ($filearray=file(CONFIG_AUTH_F)) {                // read file into array
    foreach ($filearray as $txt) {                    // scan array for port
      if(preg_match("/^\s*port\s*=\s*(\d+)/", $txt)){ // test for match 
        $new_array[] = $new_line;                     // found add new line 
      }
      else{                                           // No match
        $new_array[] = $txt;                          // Save original line
      }
    }
 }
 $str = implode($new_array);                   // Convert array to string
 file_put_contents(CONFIG_AUTH_F,$str);        // Save to file
}
// ================================================ END Set Mongo portAuth ====
  • This function is almost identical to set_mongo_port_no_auth($new_port)
  • Difference are:
  1. Function name change
  2. Uses a different configuration file


Top

get_mongo_port_auth()

// === Get Mongo port Auth ====================================================
function get_mongo_port_auth(){
  if ($filearray=file(CONFIG_AUTH_F)) {      // read file into array
    foreach ($filearray as $txt) {           // scan array for port
 
      if(preg_match("/^\s*port\s*=\s*(\d+)/", $txt,$match)){ // test save $match 
       $mongo_port =  $match[1];             // match found save port number 
       break;                                // give up nothing else to do
      }
    }
  }
  else {                                     // failed to read file
    echo "Cannot read the file";
  }
  return $mongo_port;
}
// =============================================== END Get Mongo port Auth ====
  • This function is almost identical to get_mongo_port_no_auth()
  • Difference are:
  1. Function name change
  2. Uses a different configuration file

Test

Give the test script a workout, ensure it correctly updates the configuration files and does not blow them apart.

When you have finished copy the four functions to the include file. You can delete the batch file (Run_port.bat) and test script (run_port.php).

Remember to restore port to 27017 in both configuration files.

Top

Get and set Admin name password file

Admin nameand password are changeable parameter. Before using we need to read their values from a file.

In our final application we will provide a user with the option of changing these.

Two functions are required (set-name-password and get-name-password) these are specific to authentications.

Create a new batch file Run_pwd.bat with following content:

TITLE UNIFORM SERVER - Run cmd
COLOR B0
@echo off
cls

cd ..\..\php
php.exe -c mongo_tutorial_cli.ini ..\mongo_tutorial\a_test\run_pwd.php

pause

EXIT
  • This will run our new script run_pwd.php
  • pause - Prevents window closing allowing us to view any error messages and array we print to the screen.

New test script

Create a new test script run_pwd.php with the following content:

<?php
chdir(dirname(__FILE__)); // Change wd to this files location
include_once "mongo_db_inc.php";

set_name_pwd("fred","123456");

$npwd_array = get_name_pwd_array();
 print_r($npwd_array);

=== Delete this and replace with two functions shown below =====

?>
  • First function call sets a name and password
  • Second function call receives an array containing name and password.
  • This array is displayed.

Top

get_name_pwd_array()

//=== Get name password array =================================================
function get_name_pwd_array(){
  $str = file_get_contents(NAME_PWD_F);   // Read file into string
  $str = trim( $str);                     // Clean
  $name_pwd__array  = explode(":",$str);  // Split at Separator ":"
  $new_array[] = $name_pwd__array[0];     // name
  $new_array[] = $name_pwd__array[1];     // password
  return $new_array;                      // return namd and password
}
//============================================ END Get name password array ====
  1. Read file into a string
  2. A user may have entered a space or new-line hence clean.
  3. Create an array with just the name and password.
  4. You can just return this array
  5. However a new array is created to show component parts.
  6. This new array is returned.

Top

set_name_pwd($name,$password)

//=== Set name password =======================================================
function set_name_pwd($name,$password){
  file_put_contents(NAME_PWD_F,$name.":".$password);     // Save string to file
}
//======================================================= Set name password ===
  • OK! Why bother with such a small function?
  • It hides detail we are not interested in such as the path.
  • It’s a personal choice use whatever you prefer.

Top

Test

Give the test script a workout, ensure it correctly updates name and password.

When you have finished copy the two functions to the include file. You can delete the batch file (Run_pwd.bat) and test script (run_pwd.php).

Remember to restore name and password to root:root in file mongo_name_password file

Top

Summary

That was a long session I trust it has sparked a few ideas and inspired you to follow a bit more of this tutorial.

If I have lost that, its not an issue may be a little snippet of code has caught your eye. Hey! May be it has encouraged you to look a little deeper into PHP CLI scripting.

With the foundations (components/functions) in place we can start the fun stuff.

Next part of this tutorial looks at starting MongoDB


Top