martes, 2 de diciembre de 2014

Export from MySQL to CSV

Export from MySQL to CSV

Using command line tools to export data from a MySQL database into a CSV file is quite easy. Here's how:
mysql -uexampleuser -pletmein exampledb -B -e "select * from \`person\`;" | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > filename.csv
Here is some sample output of the above:
"id","username","group","password"
"1","tux","admin","5f4dcc3b5aa765d61d8327deb882cf99"
"2","tlugian","admin","5f4dcc3b5aa765d61d8327deb882cf99"
"3","saiyuki","admin","5f4dcc3b5aa765d61d8327deb882cf99"
"4","fred","staff","5f4dcc3b5aa765d61d8327deb882cf99"
"5","barney","staff","5f4dcc3b5aa765d61d8327deb882cf99"
"6","wilma","admin","5f4dcc3b5aa765d61d8327deb882cf99"
And now for the explanation:
Starting with the MySQL command. I wont explain the -u and -p options they are straight forward (if in doubt man mysql). The -B option will delimit the data using tabs and each row will appear on a new line. The -e option denotes the command to run once you have logged into the database. In this case we are using a simple SELECT statement.
Onto sed. The command used here contains three seperate sed scripts:
s/\t/","/g;s/^/"/        <--- this will search and replace all occurences of 'tabs' and replace them with a ",".
;s/$/"/;    <--- This will place a " at the start of the line.
s/\n//g    <---- This will place a " at the end of the line.
After running the result set through sed we redirect the output to a file with a .csv extension.
Regards, Bawdo2001 

jueves, 25 de septiembre de 2014

NODE JS.


Globals.js contains configuration 
use var winston = require('winston');  //a multi-transport async logging library for node.js
config 
var logger = new (winston.Logger)({  
  transports: [  
   new (winston.transports.Console)({ json: true, timestamp: true }),  
   new winston.transports.File({ filename: __dirname + '/logs/backup.log', json: false })  
  ],  
  exceptionHandlers: [  
   new (winston.transports.Console)({ json: true, timestamp: true }),  
   new winston.transports.File({ filename: __dirname + '/logs/exceptions.log', json: false })  
  ],  
  exitOnError: false  
 });  
 //Store configuration as objects for example  
 var config = {};  
 // MySQL configuration  
 config.mysql = {};  

 config.mysql.client_qa = {  
     user:'user',  
     password:'mipass',  
     host:'localhost'  
 };  
//In Node, things are only visible to other things in the same file. By things, I mean variables, functions, classes and class members. Exports allow to access the exported variables in other file with require statement.
exports.header = header;
exports.config = config;

exports.logger = logger;
//exports is a module 

Main.js //Is the node executed file contains all the instructions to be executed. 

var chokidar = require('chokidar'); //A neat wrapper around node.js fs.watch / fs.watchFile.
var sleep = require('sleep'); //Add sleep() and usleep() to nodejs. This is mainly useful for debugging.
var header = require('./Globals').header();  
 var config = require('./Globals').config;  
 var xmlHandler = require('./XMLHandler'); //The XMLandler.js   
 var veo = chokidar.watch(config.xml_deposit(config.msos[0]), {ignored: /^\./, persistent: true});  
 //chokidar manage actions for add, change, unlink  
 veo  
  .on('add', function(path) {  
      console.log('File', path, 'has been added');  
      if (path.substr(-3) == "xml" ){  
           if (path.indexOf(config.msos[0]) >= 0){  
                var msoS = config.msos[0];  
                console.log("New File Received ("+new Date()+") : [MSO] "+msoS+" [Path] "+config.xml_deposit(msoS)+" [FileName] "+path.substr(path.lastIndexOf("/")+1) );  
                sleep.sleep(5);  
                xmlHandler.handleFile(msoS, path.substr(path.lastIndexOf("/")+1)); //Here we are going to handle the xml File  
           }  
      }  
  })  
  .on('change', function(path) {  
      console.log('File', path, 'has been changed');  
  })  
  .on('unlink', function(path) {  
      console.log('File', path, 'has been removed');  
  })  
  .on('error', function(error) {  
       console.error('Error happened', error);  
  })  

XML Handler.js 
var mysql = require('mysql');  
 var fs           = require('fs');  
 var xml2js      = require('xml2js');  
 var config = require('./Globals').config;  
 var logger = require('./Globals').logger;  
 var parser = new xml2js.Parser();  
 var system = require('child_process');  
 var filename = "";  
 var mso           = "";  
 var error      = false;  
 var mysql_config;  
 var client;  
 var http =require("http");  
 function handleFile(m, fn){  
      filename = fn;  
      mso = m;  
      fs.readFile(config.xml_deposit(mso)+filename, handleXML);  
 }  
 function handleXML(err, data) {  
      if (err){  
           system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_error(mso)+filename]);  
           system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_backup()+filename]);  
           system.spawn('rm', [config.xml_deposit(mso)+filename]);  
           throw new Error('['+mso+'][file_error] - Error en archivo '+filename+' marca tener un error de lectura de archivo eviando archivo a '+config.xml_error(mso)+filename+" e ignorando flujo");  
      } else {  
           parser.parseString(data, handleParsedData);  
      }  
 }  
 function handleParsedData(err, objectXML){  
      if (err){  
           system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_error(mso)+filename]);  
           system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_backup()+filename]);  
           system.spawn('rm', [config.xml_deposit(mso)+filename]);  
           throw new Error('['+mso+'][sintaxis] - Error en archivo '+filename+' marca tener un error de sintaxis XML enviando archivo a '+config.xml_error(mso)+filename+" e ignorando flujo");  
      } else {  
           var proveedor = objectXML.root.encabezado[0].proveedor[0];  
           var inicial = objectXML.root.encabezado[0].periodo[0].$.inicial;  
           var final = objectXML.root.encabezado[0].periodo[0].$.final;  
           var movimientos = objectXML.root.encabezado[0].numero_movimientos[0];  
           //Step 0: Validate that the number of "movimientos" reported on the XML is actually the number that exist in it.  
           if (movimientos != objectXML.root.movimiento.length){  
                system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_error(mso)+filename]);  
                system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_backup()+filename]);  
                system.spawn('rm', [config.xml_deposit(mso)+filename]);  
                throw new Error('['+mso+']['+movimientos+']['+objectXML.root.movimiento.length+'] - Error en archivo '+filename+' marca tener '+movimientos+' movimiento(s) cuando en realidad hay '+objectXML.root.movimiento.length+' movimiento(s) enviando archivo a '+config.xml_error(mso)+filename+" e ignorando flujo");  
           } else {  
                //Step 1: Insert the XML header in MySQL DB  
                mysql_config = config.mysql;  
                client = mysql.createPool(mysql_config.client_qa);           
             insertaXML(proveedor, inicial, final, movimientos, objectXML);  
           }                      
      }            
 }  
 function insertaXML (proveedor, inicial, final, movimientos, objectXML) {  
      var queryStr = "INSERT INTO `msodb`.`xml` (`id` ,`proveedor` ,`inicial` ,`final` ,`movimientos`) VALUES (NULL , '"+proveedor+"', '"+inicial+"', '"+final+"', "+movimientos+");";  
      client.getConnection(function (err0, connection) {  
           if (err0){  
                system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_backup()+filename]);  
                system.spawn('rm', [config.xml_deposit(mso)+filename]);  
                throw new Error('['+mso+']['+filename+'] - Error en MySQL no hay conexión, se requiere ingestar nuevamente el archivo.');  
           } else {  
                connection.query('USE ' + mysql_config.database);  
                connection.query(queryStr, function (err, results, fields) {  
                          if (err) {  
                               logger.info(queryStr);  
                               console.log(err);  
                          } else {  
                               if (results.affectedRows == 1){                              //Step 2: Insert the movements in the MySQL DB  
                               getEmail(results.insertId, proveedor, objectXML, connection);  
                        //  insertaMovimientos(results.insertId, proveedor, objectXML, connection);  
                          } else {  
                               logger.info(queryStr);  
                          }       
                     }       
                });  
           }  
      });            
 }  
 function getEmail(xml,mso,objeto,connection){  
     var contracts= [];  
     var msoId = {  
       "VEO" : 1,  
       "CABLEVISION" : 2,  
       "CABLEMAS" : 3,  
       "SKY" : 4,  
     };  
     for (var x = 0; x < objeto.root.movimiento.length; x++ ){  
       contracts[x]= objeto.root.movimiento[x].id[0];  
     }  
     jsonObject = JSON.stringify({"contracts":contracts.join(), "mso":msoId[mso]});  
     var emails="";  
         var postheaders = {  
           'Content-Type' : 'application/json',  
           'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')  
         };  
          var options = {  
           host: config.ws.host,  
           port: config.ws.port,  
           path: config.ws.path,  
           method: config.ws.method,  
           headers: postheaders  
          };  
         // do the POST call  
         var reqPost = http.request(options, function(res) {  
           res.on('data', function(d) {  
             emails+=d;  
             insertaMovimientos(xml,mso,objeto,connection,emails);  
           });  
         });  
         // write the json data  
         reqPost.write(jsonObject);  
         reqPost.end();  
         reqPost.on('error', function(e) {  
           console.error(e);  
         });   
 }  
 function insertaMovimientos(xml, mso, objeto, connection,emails){  
     var emailsArray=JSON.parse(emails);  
      error = false;       
      for (var x = 0; x < objeto.root.movimiento.length; x++ ){  
           var idmso           = objeto.root.movimiento[x].id;  
           var nombre          = objeto.root.movimiento[x].usuario[0].nombre;  
           if (objeto.root.movimiento[x].usuario[0].direccion != null){  
                var calle          = objeto.root.movimiento[x].usuario[0].direccion[0].calle;  
                var ciudad          = objeto.root.movimiento[x].usuario[0].direccion[0].ciudad;  
                var colonia          = objeto.root.movimiento[x].usuario[0].direccion[0].colonia;  
                var municipio     = objeto.root.movimiento[x].usuario[0].direccion[0].municipio;  
                var delegacion     = objeto.root.movimiento[x].usuario[0].direccion[0].delegacion;  
                var numero_exterior     = objeto.root.movimiento[x].usuario[0].direccion[0].numero_exterior;  
                var numero_interior     = objeto.root.movimiento[x].usuario[0].direccion[0].numero_interior;  
                var estado          = objeto.root.movimiento[x].usuario[0].direccion[0].estado  
                var pais          = objeto.root.movimiento[x].usuario[0].direccion[0].pais  
                var cp               = objeto.root.movimiento[x].usuario[0].direccion[0].cp;  
           } else {  
                var calle, ciudad, colonia, municipio, delegacion, numero_exterior, numero_interior, estado, pais, cp;  
                calle = ciudad = colonia = municipio = delegacion = numero_exterior = numero_interior = estado = pais = cp = 'n/a';  
                cp = '-1';  
           }  
           //var email          = objeto.root.movimiento[x].usuario[0].email;  
           var fase          = objeto.root.movimiento[x].fase+"";  
           var tipo          = objeto.root.movimiento[x].tipo;  
           if (fase.toUpperCase() == "COBRADO"){  
                var monto_facturado          = objeto.root.movimiento[x].monto_facturado;  
           } else if (fase.toUpperCase() == "PAGADO"){  
                var monto_facturado          = objeto.root.movimiento[x].monto_pagado;  
           } else if (fase.toUpperCase() == "EMITIDO"){  
                var monto_facturado          = objeto.root.movimiento[x].monto_facturado;  
           } else {  
                var monto_facturado          = objeto.root.movimiento[x].monto_facturado;  
           }  
           var fecha          = objeto.root.movimiento[x].fecha;            
           var sc               = "0";  
         var email=findEmail(emailsArray,idmso);  
           var queryStr = "INSERT INTO `msodb`.`movimiento` (`id_xml`, `sc`, `mso`, `idmso`, `nombre`, `calle`, `ciudad`, `colonia`, `municipio`, `delegacion`, `numero_exterior`, `numero_interior`, `estado`, `pais`, `cp`, `email`, `fase`, `tipo`, `monto`, `concepto`, `fecha`) VALUES ("+xml+", '"+sc+"', '"+mso.toUpperCase()+"', '"+idmso+"', '"+nombre+"', '"+calle+"', '"+ciudad+"', '"+colonia+"', '"+municipio+"', '"+delegacion+"', '"+numero_exterior+"', '"+numero_interior+"', '"+estado+"', '"+pais+"', '"+cp+"', '"+email+"', '"+fase.toUpperCase()+"', '"+tipo+"', "+monto_facturado+", 'Suscripción Mensual SVOD', '"+fecha+"');";  
           queryStr = queryStr.split("[object Object]").join("n/a");  
           connection.query(queryStr, function (err, results, fields) {  
                     if (err) {  
                               if (err.code == "ER_DUP_ENTRY"){  
                                    var queryUpdate = queryStr.substr(queryStr.indexOf("VALUES (")+8);  
                                    queryUpdate = queryUpdate.substr(0,queryUpdate.length-2);  
                                    var items = queryUpdate.split(',');  
                             console.log(err);  
                                    var queryUpdate = "id_xml="+items[0]+",sc="+items[1]+",mso="+items[2]+",idmso="+items[3]+",nombre="+items[4]+",calle="+items[5]+",ciudad="+items[6]+",colonia="+items[7]+",municipio="+items[8]+",delegacion="+items[9]+",numero_exterior="+items[10]+",numero_interior="+items[11]+",estado="+items[12]+",pais="+items[13]+",cp="+items[14]+",email="+items[15]+",fase="+items[16]+",tipo="+items[17]+",monto="+items[18]+",concepto="+items[19]+",fecha="+items[20];  
                                    queryUpdate = "UPDATE movimiento SET "+queryUpdate+" WHERE mso = '"+mso.toUpperCase()+"' AND idmso = "+items[3]+";";  
                                    actualizaMovimientos(queryUpdate, connection, objeto.root.movimiento.length, x, error);  
                               } else {  
                                    logger.info(queryStr);  
                                    console.log(err);  
                                    error = true;       
                                    finalStep( objeto.root.movimiento.length, x, error, connection);  
                               }  
                     } else {  
                               if (results.affectedRows == 1){                                   error = false;  
                                    finalStep( objeto.root.movimiento.length, x, error, connection);  
                               } else {  
                                    error = true;  
                                    logger.info(queryStr);  
                                    finalStep( objeto.root.movimiento.length, x, error, connection);  
                               }       
                     }  
           });  
      }  
 }  
 function actualizaMovimientos(queryStr, connection, original, count, error){  
      connection.query(queryStr, function (err, results, fields) {  
           if (err) {  
                logger.info(queryStr);  
                console.log(err);  
                error = true;       
                finalStep( original, count, error, connection);  
           } else {  
                if (results.affectedRows == 1){  
                     error = false;  
                     finalStep( original, count, error, connection);  
                } else {  
                     error = true;  
                     logger.info(queryStr);  
                     finalStep( original, count, error, connection);  
                }  
           }  
      });  
 }  
 function finalStep(original, count, error, connection){  
      if (original == count){  
           if (error){  
                system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_error(mso)+filename]);  
                system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_backup()+filename]);  
                system.spawn('rm', [config.xml_deposit(mso)+filename]);  
           } else {  
                system.spawn('cp', ['-r', config.xml_deposit(mso)+filename, config.xml_backup()+"/ok/"+filename]);  
                system.spawn('rm', [config.xml_deposit(mso)+filename]);  
           }       
           connection.end();       
      }  
 }  
 function findEmail(emails,contract){  
   for (var x=0; x< emails.length; x++){  
     if (emails[x].contract==contract)  
       return emails[x].email;  
   }  
   return null;   
 }  
 exports.handleFile = handleFile;  

martes, 9 de septiembre de 2014

OCI Driver installation on MAC



My current project involves using PHP with an Oracle database. Oracle apparently embraces PHP warmly and as such supports an open source database driver for the environment called OCI8. As a Mac user I was looking to use OS X's built-in Apache and PHP setup, which like many PHP installations does not have the Oracle OCI8 driver installed or enabled. It took me some time and research to get it up and running. I was using Oracle Express, a limited capability, free-ish version of Oracle's database. Oracle Express was installed on a separate Windows machine as it cannot run or be installed on Snow Leopard. I also assume that you enabled PHP in your Apache configuration (/etc/apache2/httpd.conf) and have a /etc/php.ini by copying it from/etc/php.ini.default.
OCI8 relies on OS X having several client libraries and tools from Oracle installed on OS X. For most intents and purposes download the 64-bit version of the following files under the title "Version 10.2.0.4 (64-bit)": 
Registration is required for all downloads.
Once downloaded, unzip all three files, which will look like this on your file system
Now, create a separate directory (which I called instantclient_10_2) and copy the contents of all the files included in these subfolders into it, which will look something like this:
The next step is to copy the necessary files into your OS X dynamic library and bin directories (as described here). Open a terminal window and go to the directory above the one you created containing all the files you unzipped.
sudo cp instantclient_10_2/sdk/include/*.h /usr/include
sudo cp instantclient_10_2/sqlplus /usr/bin
sudo cp instantclient_10_2/*.dylib /usr/lib
sudo cp instantclient_10_2/*.dylib.* /usr/lib
Now move to the /usr/lib directory and create the following link:
sudo ln -s libclntsh.dylib.10.1 libclntsh.dylib
To test, open another terminal window or tab, and try to run Oracle's SQL*Plus tool using
/usr/bin/sqlplus. If it worked, you are almost there. Exit SQL*Plus by entering quitor simply Ctrl+C.
You now have the Oracle tools installed. Now, to install OCI8, which we will install from the PECL repository. In a terminal window enter
sudo pecl install oci8
[If you see an error here, you may not have Pecl or Pear (PHP package managers) installed. In that case look at these installation instructions]
OCI8 will download and will eventually give you the prompt:
Please provide the path to the ORACLE_HOME directory. Use 'instantclient,/path/to/instant/client/lib' if you're compiling with Oracle Instant Client [autodetect] :
In response enter:
instantclient,/usr/lib
We are doing this because Oracle is not installed on our local machine. If it were we would respond with the path to Oracle's installation directory. Once entered, PECL will compile and build OCI8. Once done, it will ask you to enable the extension in your PHP configuration. To do that, open php.ini and add the line (normally among the list of extensions):
extension=oci8.so
Once done, you can start Apache again using
sudo apachectl start
To test the installation, enable the HR account in your Oracle installation and run a PHP file such as (make sure you replace the password and database server IP or name in the code):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
&lt; ?php
$c = oci_connect(&#39;hr&#39;, <password here="">, &#39;<server ip="" name="" or="">/XE&#39;);
$s = oci_parse($c, &#39;select city, postal_code from locations&#39;);
oci_execute($s);
print &#39;&#39;;
while ($row = oci_fetch_array($s, OCI_NUM+OCI_RETURN_NULLS)) {
print &#39;&#39;;
foreach ($row as $item)
print &#39;&#39;;
print &#39;&#39;;
}
print &#39;
<table border="&quot;1&quot;">
 <tbody>
  <tr>
   <td>&#39;.htmlentities($item).&#39;</td>
  </tr>
 </tbody>
</table>
&#39;;
oci_free_statement($s);
?&gt;
</server></password>



I’m currently working on a project that requires data from a student information system (PowerSchool).  PowerSchool uses an Oracle database for it’s data layer so it became necessary to install the oci8 extension for my local development environment.  Google didn’t provide much in terms of start to finish steps, so I thought I’d detail my steps here to hopefully help someone else save some time.
My current local environment includes:
  • OS 10.9.2 (Mavericks)
  • MAMP Pro 3.0.5 (PHP Version 5.5.10)
  • Xcode (with command line tools) *required
We’re going to use PECL to install the extension.

To build the oci8 extension, you need the Oracle Instant Client Package -Basic and SDK.  Both of these can be downloaded here:

Note: The downloads are platform specific.  The above link is for the Mac OS X (Intel x86).  I downloaded Version 11.2.0.4.0 (64-bit)

You also need to download php for building the extension. Download here:

http://php.net/downloads.php
Note: Download the version pertinent to your MAMP installation.  I will use 5.5.10 for the purposes of this article.

Extract php:

tar zxf ~/Downloads/php-5.5.10.tar.bz2

Install the php source into MAMP:

mkdir /Applications/MAMP/bin/php/php5.5.10/include
mv ~/Downloads/php-5.5.10 /Applications/MAMP/bin/php/php5.5.10/include/php

Run configure to generate appropriate header files:

cd /Applications/MAMP/bin/php/php5.5.10/include/php
./configure --without-iconv

Extract the instantclient-basic zip file (instantclient-basic-macos.x64-11.2.0.4.0.zip):

unzip ~/Downloads/instantclient-basic-macos.x64-11.2.0.4.0.zip

Move the extracted folder, instantclient_11_2 to MAMP:

mv ~/Downloads/instantclient_11_2 /Applications/MAMP/bin/php/php5.5.10/lib/php/

Extract the instantclient-sdk zip file (instantclient-sdk-macos.x64-11.2.0.4.0.zip):

unzip ~/Downloads/instantclient-sdk-macos.x64-11.2.0.4.0.zip

Move the sdk folder inside the instantclient_11_2 we moved earlier:

mv ~/Downloads/instantclient_11_2/sdk /Applications/MAMP/bin/php/php5.5.10/lib/php/instantclient_11_2/

Create a symbolic link to the library:

cd /Applications/MAMP/bin/php/php5.5.10/lib/php/instantclient_11_2
ln -sf libclntsh.dylib.11.1 libclntsh.dylib


BREW INSTALL AUTOCONF (if phpize failed)



Use PECL to build and install the oci8 module:

cd /Applications/MAMP/bin/php/php5.5.10/bin/
./pecl install oci8

During the installation process, it will ask for the ORACLE_HOME path.  Use the following line:

instantclient,/Applications/MAMP/bin/php/php5.5.10/lib/php/instantclient_11_2

The build process should continue and end with something like:

...
Installing '/Applications/MAMP/bin/php/php5.5.10/lib/php/extensions/no-debug-non-zts-20121212/oci8.so'
install ok: channel://pecl.php.net/oci8-2.0.8
configuration option "php_ini" is not set to php.ini location
You should add "extension=oci8.so" to php.ini

The instantclient library has some hardcoded paths we need to take care of:

sudo mkdir -p /ade/b/3071542110/oracle/rdbms/lib/
sudo ln -sf /Applications/MAMP/bin/php/php5.5.10/lib/php/instantclient_11_2/libclntsh.dylib.11.1 /ade/b/3071542110/oracle/rdbms/lib/libclntsh.dylib.11.1
sudo mkdir -p /ade/dosulliv_ldapmac/oracle/ldap/lib/
sudo ln -sf /Applications/MAMP/bin/php/php5.5.10/lib/php/instantclient_11_2/libnnz11.dylib /ade/dosulliv_ldapmac/oracle/ldap/lib/libnnz11.dylib
We also need to update the DYLD_LIBRARY_PATH for MAMP.

Edit /Applications/MAMP/Library/bin/envvars with your favorite editor:

nano /Applications/MAMP/Library/bin/envvars

Add the following line just before “export DYLD_LIBRARY_PATH”:

DYLD_LIBRARY_PATH="/Applications/MAMP/bin/php/php5.5.10/lib/php/instantclient_11_2:$DYLD_LIBRARY_PATH"
Finally, in MAMP, we need to tell php to load the oci8 extension per the instructions in the build.
In MAMP, choose File -> Edit Template -> PHP -> PHP 5.5.10 php.ini

Find the section titled “Extensions”, add:

extension=oci8.so
Save the file and restart MAMP Pro.  You should now be able to use the oci extension in your php project!

viernes, 15 de agosto de 2014

Implementing Web Service REST with SLIM microframework

A Quick Guide to implement a REST Web Service with database connection using SLIM MicroFramework

1.- SLIM INSTALLATION
Install composer in your project:
curl -s https://getcomposer.org/installer | php
Create a composer.json file in your project root:
{
    "require": {
        "slim/slim": "2.*"
    }
}
Install via composer:
php composer.phar install
Add this line to your application’s index.php file:
<?php
require 'vendor/autoload.php';

2.- Testing installation (Create an index.php to test) 
$app = new \Slim\Slim(array(
    'debug' => true
        ));

$app->get('/', function () {
    echo 'Hola Mundo'; 
});

$app->run();



3.- Optional Managing of VIRTUAL HOST  
<VirtualHost local.televisa:8081>
    ServerName local.pruebas
    DocumentRoot /Users/Tomas/projects/empresa/php
    SetEnv APPLICATION_ENV "development"
    <Directory /Users/Tomas/projects/empresa/php>
        DirectoryIndex index.php
        AllowOverride All
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

4.-Dir Structure
4a) config.xml: Logger configuration file
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://logging.apache.org/log4php/">
    <appender name="myAppender" class="LoggerAppenderFile">
        <layout class="LoggerLayoutPattern">
            <param name="conversionPattern" value="%date [%logger] %message%newline" />
        </layout>
        <param name="file" value="/Users/Tomas/projects/empresa/php/WSSubscriber/logs/WSSS.log" />
    </appender>
    <root>
        <level value="DEBUG" />
        <appender_ref ref="myAppender" />
    </root>
</configuration>
4b) veo-config.ini: Database configuration and other conf parameters for the application.
[database]
host = localhost
username = dummyuser
password = dummypass
dbname = databasename
type = mysql
charset = 'utf8'

4c) GenericDAO:
<?php
include_once __DIR__.'/../init.php';
include_once __HELPER_PATH__.'/VeoConfiguration.php';

class GenericDAO {

    private $logger = NULL;
    
    protected $pdo_obj = NULL;     // Stores the open connection PDO object
    private $connection_string = NULL; // Used to build the database connection
    private $db_type = NULL;   // Stores the database type
    private $db_host = NULL;
    private $db_user = NULL;
    private $db_pass = NULL;
    private $db_name = NULL;
    private $db_charset = NULL;
    private $is_active = false;               // Checks to see if the connection is active

    protected $pdo_obj_rr = NULL;     // Stores the open connection PDO object
    private $connection_string_rr = NULL; // Used to build the database connection
    private $db_type_rr = NULL;   // Stores the database type
    private $db_host_rr = NULL;
    private $db_user_rr = NULL;
    private $db_pass_rr = NULL;
    private $db_name_rr = NULL;
    private $db_charset_rr = NULL;
    private $is_active_rr = false;               // Checks to see if the connection is active

    public function __construct() {
        $config = VeoConfiguration::getInstance();
        $this->logger = Logger::getLogger("GenericDAO");
        $this->db_host = $config->get('database', 'host');
        $this->db_user = $config->get('database', 'username');
        $this->db_pass = $config->get('database', 'password');
        $this->db_name = $config->get('database', 'dbname');
        $this->db_type = $config->get('database', 'mysql');
        $this->db_charset = $config->get('database', 'charset');
        $this->connection_string = "mysql:host=" . $this->db_host . ";dbname=" . $this->db_name;

        $this->db_host_rr = $config->get('databaserr', 'host');
        $this->db_user_rr = $config->get('databaserr', 'username');
        $this->db_pass_rr = $config->get('databaserr', 'password');
        $this->db_name_rr = $config->get('databaserr', 'dbname');
        $this->db_type_rr = $config->get('databaserr', 'mysql');
        $this->db_charset_rr = $config->get('databaserr', 'charset');
        $this->connection_string_rr = "mysql:host=" . $this->db_host_rr . ";dbname=" . $this->db_name_rr;

        return $this;
    }

    /*
     * only one connection allowed
     */
    protected function connect() {
        if (!$this->is_active) {
            try {
                $attrs = array(
                    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES " . $this->db_charset
                );
                $this->pdo_obj = new PDO($this->connection_string, $this->db_user, $this->db_pass, $attrs);
                $this->pdo_obj->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                
                $this->is_active = true;
            } catch (PDOException $e) {
                $this->logger->error("ERROR:" . $e->getMessage());
                $this->logger->error("ERROR:" . $e->getTraceAsString());
                throw $e;
            }
        }
        return $this->is_active;
    }

    protected function connect_rr(){        
        if (!$this->is_active_rr) {
            try {
                $attrs = array(
                    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES " . $this->db_charset_rr
                );
                $this->pdo_obj_rr = new PDO($this->connection_string_rr, $this->db_user_rr, $this->db_pass_rr, $attrs);
                $this->pdo_obj_rr->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                
                $this->is_active_rr = true;
            } catch (PDOException $e) {
                $this->logger->error("ERROR:" . $e->getMessage());
                $this->logger->error("ERROR:" . $e->getTraceAsString());
                throw $e;
            }
        }
        return $this->is_active_rr;
    }

    protected function disconnect() {
        $isDisconnect = false;
        if ($this->is_active) {
            unset($this->pdo_obj);
            $this->is_active = false;
            $isDisconnect = true;
        }
        return $isDisconnect;
    }

     protected function disconnect_rr() {
        $isDisconnect = false;
        if ($this->is_active_rr) {
            unset($this->pdo_obj_rr);
            $this->is_active_rr = false;
            $isDisconnect = true;
        }
        return $isDisconnect;
    }

    /*
     * SELECT (any)
     * Required: $sqlSelect
     */
    public function select($sqlSelect) {
        $this->connect_rr();        
        $exception = NULL;
        $arrayResult = NULL;
        try {
            $sql = $this->pdo_obj_rr->prepare($sqlSelect);
            $sql->execute();
            $arrayResult = $sql->fetchAll(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            $exception = $e;
            $this->logger->error("ERROR:" . $e->getMessage());
            $this->logger->error("ERROR:" . $e->getTraceAsString());
        } 
        $this->disconnect_rr();
        if($exception){
            throw $exception;
        }            
        return $arrayResult;
    }

    /*
     * INSERT
     * Required: $strInsert sql insert
     */
    public function insert($strInsert, $getLastId = FALSE) {
        $exception = NULL;
        $totalRows = -1;
        $this->connect();
        try {
            $ins = $this->pdo_obj->prepare($strInsert);
            $ins->execute();
            if ($getLastId) {
                $totalRows = $this->pdo_obj->lastInsertId();
            } else {
                $totalRows = $ins->rowCount();
            }
        } catch (PDOException $e) {
            $this->logger->error("ERROR:" . $e->getMessage());
            $this->logger->error("ERROR:" . $e->getTraceAsString());
            $exception = $e;
        } 
        $this->disconnect();
        if($exception){
            throw $e; 
        }
        return $totalRows;
    }

    /*
     * DELETE
     * Required: Stament to sql delete
     */

    public function delete($strDelete) {
        $exception = NULL;
        $totalRows = -1;
        $this->connect();
        try {
            $del = $this->pdo_obj->prepare($strDelete);
            $del->execute();
            $totalRows = $del->rowCount();
        } catch (PDOException $e) {
            $this->logger->error("ERROR:" . $e->getMessage());
            $this->logger->error("ERROR:" . $e->getTraceAsString());
            $exception = $e; 
        }
        $this->disconnect();
        if($exception){
            throw $e; 
        }
        return $totalRows;
    }

    /*
     * UPDATE
     * Required: $strUpdate
     */
    public function update($strUpdate) {
        $exception = NULL;
        $totalRows = -1;
        $this->connect();
        try {
            $upd = $this->pdo_obj->prepare($strUpdate);
            $upd->execute();
            $totalRows = $upd->rowCount();            
        } catch (Exception $e) {
            $this->logger->error("ERROR:" . $e->getMessage());
            $this->logger->error("ERROR:" . $e->getTraceAsString());
            $exception = $e; 
        }
        $this->disconnect();
        
        if($exception){
            throw $e;
        }
        return $totalRows;
    }
}

?>

4d) VeoServicesDAO DAO APP specific functions.
<?php

include_once __DIR__ . '/../../init.php';
include_once __DATA_PATH__ . '/GenericDAO.php';

/**
 * Description of VeoServicesDAO
 *
 */
class VeoServicesDAO extends GenericDAO {

    private $logger;

    public function __construct() {
        parent::__construct();
        $this->logger = Logger::getLogger('VeoServicesDAO');
    }
 /**
     * Looks for entitlement using the contract number and the mso_id.
     * @param string $contract The contract code. 
     * @param string $mso_id The mso_id
     * @return array The subscriber information.
     */
    public function getEntitlementByContractAndCityId($contract, $city=null) {
        $sqlSelect = 'SELECT * FROM entitlement WHERE contract = "' . $contract . '"';
        if (!empty ($city))
                $sqlSelect.= ' AND city_id = "' .$city.'"';
        $this->logger->debug('getEntitlementByContractAndCity: ' . $sqlSelect);
        $result = $this->select($sqlSelect);
        if (count($result) === 1 )
            return $result[0];
        else if(count($result) > 1)
            return 1;
        else 
            return NULL;
    }
}

?>

4e) VeoConfiguration A singleton pattern Class implementation to get config file.
<?php

include_once __DIR__ . '/../init.php';

/**
 * This class implements the singleton pattern to return configuration values 
 * without opening and closing the file every time needed.
 * 
 * @author Abraham Soto
 */
class VeoConfiguration {
    
    //The reference to the file
    private $file_ini;
    
    //The ¡nstance of the class that will be returned when needed.
    private static $instance = NULL;
    
    /** Constructor of the class.*/
    private function __construct() {
        $this->file_ini = parse_ini_file(__CONFIG_FILE_INI__, true);
    }
    
    /** Singleton method, returns an instance of this class. */
    public static function getInstance(){
        if(self::$instance == NULL){
            self::$instance = new VeoConfiguration();
        }
        return self::$instance;
    }
    
    /**
     * This method returns the value set in the config file.
     * @param type $section optional, the section to which the config property belongs to.
     * @param type $name The name of the property.
     * 
     * @return string returns an string with the value obtained from the config file. if the value is not in the file returns NULL.
     */
    public function get($section, $name){
        return isset($this->file_ini[$section][$name]) ? 
            $this->file_ini[$section][$name] : '';
    }
    
 }
?>

4f) WSSS.log: Log file with write permissions.  

4g) Init.php Constants definition and Logger initially instantiation.
<?php
//Root path of the application.
define('__ROOT_PATH__', __DIR__);

//Path to the Config folder.
define('__CONFIG_PATH__', __ROOT_PATH__ . '/configs');

//Path to the veo-config.ini file.
define('__CONFIG_FILE_INI__', __CONFIG_PATH__ . '/veo-config.ini');
        
//Path to the helper class
define('__HELPER_PATH__', __ROOT_PATH__ . '/helpers');

//Path to the log files
define('__LOGGER_FILE_APP__', __ROOT_PATH__ . '/logs/veo_app_errors.log');

//Path to the library class
define('__LIBRARY_PATH__', __ROOT_PATH__ . '/vendor');

//Path to the dao class
define('__DATA_PATH__', __ROOT_PATH__ . '/data');
        
//Include logger and initialize it
include_once __LIBRARY_PATH__.'/log4php/Logger.php';
Logger::configure(__CONFIG_PATH__.'/config.xml');

?>

4h) index.php The main file with methods and logic implementation.
<?php

/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

require 'vendor/autoload.php';
include_once 'init.php';
include_once __DATA_PATH__ . '/dao/VeoServicesDAO.php';

$dao = new VeoServicesDAO();
$logger = Logger::getLogger("index.php");


$app = new \Slim\Slim(array(
    'debug' => false
        ));



$app->get('/', function () {
    echo 'Utilice <b>/consulta</b> para acceder al Web Service para consultar estatus de un suscriptor tomando como parametros POST contrato y opcionalmente una ciudad-<br>  Recibe POST:   <br> <b>{"contract":"value", "city":"value"}</b> <br> Regresa <br> <b>{"status":"value"}</b>'; 
});



/**
 * Consult.
 * Input:       It will take the POST containing a contract and optional parameter city.
 * Output:      Return the status for the subscriber contract. 
 * Test Cases:
 *  Success:            HTTP 200 OK
 *  Failure:            HTTP 500 Error
 *  Errors:             HTTP 400 Exception
 *      Exceptions:
 *          Missin Data Fields       HTTP 417 Exception
 * 
 * @todo finish the functions on this page
 */
$app->post('/consulta', function () use ($app, $logger,$dao) {
    $app->response()->header('Content-Type', 'application/json; charset=utf-8');
    $response = array();
    try {
        if($app->request()->getBody() === ''){
            throw new Exception('Missing Data Fields', 417);
        }
        $request = json_decode($app->request()->getBody());
        
        if(empty($request->contract)){
             throw new Exception('Missing Data Field contract', 417);
        }
            
        $city = !empty($request->city)?$request->city:NULL;
        $contract = $request->contract;
        
        $entitlement = $dao->getEntitlementByContractAndCityId($contract,$city);
        
        if (!$entitlement){
            throw new Exception('No data found', 418);
        }
        else if ($entitlement==1){
            throw new Exception('More than one register found', 419);
        }
        else{
            $response['status'] = $entitlement['account_status'];
        }
    } catch (Exception $e) {
        $response['error_code'] = $e->getCode();
        $response['error_message'] = $e->getMessage();
    }
    echo json_encode($response, JSON_UNESCAPED_UNICODE);
});
$app->run();
?>