Tuesday, May 9, 2017

Quick code to test XML-RPC and SOAP 2 in PHP using Magento 1.x

XML-RPC


require_once 'app/Mage.php';

umask(0);
Mage::app();

$host = 'http://test.com';
$user = 'user';
$pass = 'pass';  

$client = new Zend_XmlRpc_Client($host.'/api/xmlrpc/');
$session = $client->call('login', array($user,$pass));

//call resource sales_order.info
$client->call('call', array($session, 'sales_order.info', array('10000001')));

$response = $client->getLastResponse();
$data = $response->getReturnValue();
var_dump($data);

$client->call('endSession', array($session)); 

SOAP 2


ini_set("soap.wsdl_cache_enabled", "0");//no cache

$host = 'http://test.com';
$user = 'user';
$pass = 'pass';  

$client = new SoapClient($host.'/api/v2_soap/?wsdl'); 
$sessionId = $client->login($user,$pass); 
 
//check available types
//$types = $client->__getTypes();
//var_dump($types);

//check available functions
//$functions = $client->__getFunctions();
//var_dump($functions);

$result = $client->salesOrderInfo($sessionId,'900687569'); 
var_dump($result);

Wednesday, April 19, 2017

Quick way to get a backtrace in PHP

Thanks to my friend Karel Lacaci, he send me this useful code.

// DEBUG BACKTRACE START ----------------------------
$file_paths = debug_backtrace();
foreach($file_paths AS $file_path) {
echo $file_path['file'] ;
echo 'Line: ' . $file_path['line'] ;
echo 'Function: ' . $file_path['function'] ;
echo 'Class: ' . $file_path['class'] ;
}
// DEBUG BACKTRACE END ---------------------------- 

Wednesday, March 8, 2017

Using inotify to detect file chages and send a notification by PHP

First of all we need to increase the inotify watchers, by default in Linux environments this value is very low. Check this Increase inotify watchers. Next let's create a watcher to always keep watching a folder(/temp/watch), save the change in a log(watchlog.log) and send an email by PHP. By default when inotify find a change the program just close until this is run again.
There is an option -d (demon but I haven't tested)
1. Create a folder called "watchlog"(/path/to/watchlog) and create the script to watch in the folder "/temp/watch"

inotify_folder.sh
#!/bin/bash

log_dir="log/"
log_file="watchlog.log"

while true
do
ts=$(date +"%C%y%m%d")
OUTPUT="$(inotifywait -r -e modify,create,delete --format '%T %:e %w%f' --timefmt '%c' /temp/watch  | awk '{print $4" "$6" "$7}' )"
#$4 time of change
#$6 event
#$7 file path
echo "${OUTPUT}" >> $log_dir$ts$log_file
php inotify_php.php $OUTPUT
done
inotifywait is using the parameter -r to watch recursive, if there are a lot of level and files inotify can take a while to start.
the paremter -e specify wich actions we want to watch, there more actions by default.
2. Create the folder /log in the same level to save the logs. 3. Create the script that will be call by the cron to check if the script 'inotify_folder.sh' is running

inotify_cron.sh
#!/bin/bash

running=`ps auxf | grep inotify_folder | grep -v grep`
if [ -z "$running" ]
then
    /bin/bash inotify_folder.sh
fi
4. Create the PHP script to send the email

  inotify_php.php
<?php
$receivers = array('user@mail.com');
$time = $argv[1];
$event = $argv[2];
$file = $argv[3];

foreach($receivers as $receive){
	mail($receive,'Alert on file '.$file.' with a '.$event,$event.' '.$file);
}

5. Set a cron to check every one minute
*/1 * * * * root cd /path/to/watchlog; sh inotify_cron.sh

Friday, May 6, 2016

Magento Multiple Database Connection

Working with Magento 1.9 I was asked to make multiple read and write connections.
Magento has the possibility to configure read and write connections in the /app/etc/local.xml. Just set the tag use to let Magento know which one is available.

<!-- MASTER SERVER -->
<default_setup>
     <connection>
         <host>master</host>
         <username>user</username>
         <password>123456</password>
         <dbname>magento</dbname>
         <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
         <model><![CDATA[mysql4]]></model>
         <type><![CDATA[pdo_mysql]]></type>
         <pdoType><![CDATA[]]></pdoType>
         <active>1</active>
     </connection>
</default_setup>
<default_write>
     <connection>
          <use>default_setup</use>
      </connection>
</default_write>
<!-- SLAVE SERVER -->
<slave_connection>
     <connection>
           <host>slave</host>
           <username>user</username>
           <password>123456</password>
           <dbname>magento</dbname>
           <initStatements><![CDATA[SET NAMES utf8]]></initStatements>
           <model><![CDATA[mysql4]]></model>
           <type><![CDATA[pdo_mysql]]></type>
           <pdoType><![CDATA[]]></pdoType>
           <active>1</active>
      </connection>
</slave_connection>
<default_read>
      <connection>
          <use>slave_connection</use>
      </connection>
</default_read>

We can define n connections in the same config file like this test example

 
   
   test_server
   root
   123456
   magento_db
   SET NAMES utf8
   mysql4
   pdo_mysql
   
   1
 

The limit is that the connections are applied to the whole system but my idea is to set only for certain resources.
In this case I have a custom report module where I only want to make read connections in the Order table.
After overriding the Order resource Mage/Sales/Model/Resource/Order.php
Just make 3 updates

  1. Make a flag to know if its time to change the connection $reportConnection.
  2. Update function _construct() to create the custom connection and add it to the array of resources.
  3. Update function _getConnection() to decide if use the custom connection.

//flag
public $reportConnection = false;

/**
*Just add the connection defined in the local.xml 'test_read'
*/
protected function _construct(){
    $this->_init('sales/order', 'entity_id');
    $this->_resources->getConnection('test_read');
}

/**
*Make the connection if the flag is set
*/
protected function _getConnection($connectionName){
 if (isset($this->_connections[$connectionName])) {
   return $this->_connections[$connectionName];
    }

   if($connectionName == 'read' && $this->reportConnection)
        $this->_connections[$connectionName] = $this->_resources->getConnection('test_read');
   else{
   if (!empty($this->_resourcePrefix)) {
      $this->_connections[$connectionName] = $this->_resources->getConnection(
      $this->_resourcePrefix . '_' . $connectionName);
  } else {
   $this->_connections[$connectionName] = $this->_resources->getConnection($connectionName);
  }
   }
   return $this->_connections[$connectionName];
}

Last step is to make call an Order collection but using the test_read connection.
//Get the Order model
$model = Mage::getModel('sales/order');
//set the flag
$model->getResource()->reportConnection = true;
//get the collection
$collection = $model->getCollection();

Friday, May 30, 2014

How to catch emails sent with PHP on your local server


Taking the idea from Martin Valasek.
I decided to make a small change like add the extension "*.eml" for opening faster the saved emails with thunderbird at the time they are created.
Create a folder for your outgoing mail. We will create it in under /var/log/ where all the logs are stored:
$ sudo mkdir /var/log/mail

Create file /usr/local/bin/sendmail using your favorite text editor
$ sudo nano /usr/local/bin/sendmail
Add following PHP script to this new "sendmail" file:
#!/usr/bin/php
<?php
$input = file_get_contents('php://stdin');
$timeCreated = explode(" ",microtime());
$filename = tempnam('/var/log/mail',$timeCreated[1].'_'.$timeCreated[0].'_');
file_put_contents($filename.'.eml', $input);
unlink($filename);
shell_exec('thunderbird '.$filename.'.eml > /dev/null 2>/dev/null &');

 We need to link our PHP script to PHP's sendmail functionality. Edit your "php.ini" file and set the sendmail_path setting as following:
sendmail_path = /usr/local/bin/sendmail
In Ubuntu the "php.ini" is located for Apache
/etc/php5/apache2
and for Cli
/etc/php5/cli

Now we need to set permissions for new files/folders:
$ sudo chmod 755 /usr/local/bin/sendmail
$ sudo chmod 777 /var/log/mail

Restart apache:
$ sudo /etc/init.d/apache2 restart
You can now try to send an email using PHP's mail() function and check the /var/log/mail folder.
And the email will open automatically with Thunderbird when they are created.

Friday, February 7, 2014

Another way to get all stores names with their id in Magento


/**
 * Return all the stores
 * 
 * @author abelbm
 * @return array
 */
function getAllStores(){
    $stores = array();
    
    $storesData = Mage::getSingleton('adminhtml/system_store')->getStoreValuesForForm(); 
    foreach ($storesData as $storeGrandParent)
        foreach ($storeGrandParent as $storeParent)
            if(is_array($storeParent) && !empty($storeParent)){
                foreach ($storeParent as $store)
                    $stores[$store['value']] = strip_tags(trim(iconv('UTF-8', 'ASCII//TRANSLIT', $store['label'])));
            }
            
    return $stores;
}

Friday, August 16, 2013

Script to refresh Cache and Index in Magento

Let's place a file in the Magento root called "maintanance.php"
$path = '/your/magento/root');
echo("Refresh the Cache \n");
$return = shell_exec("php shell/refreshCache.php");
echo $return."\n";
echo 'Refreshing Cache';
#php shell/refreshCache.php
echo("Reindexing...this could take a while  \n");
$return = shell_exec("php shell/indexer.php --reindexall");
echo $return."\n";
#php shell/indexer.php --reindexall
Create in shell folder refreshCache.php
$magePath = 'app/Mage.php';
require_once($magePath);


try {
 $allTypes = Mage::app()->useCache();
 foreach($allTypes as $type => $blah) {
  Mage::app()->getCacheInstance()->cleanType($type);
 }
} catch (Exception $e) {
 // do something
 error_log($e->getMessage());
 Mage::log($e->getMessage());
}