Blog

Aug
04
2012

Out of Memory PHP Apache WHM and VPS

This is a quick blog post about something that took me a while to find the solution for. I was creating an upload script for a customers site and running it on my virtual server. While I was uploading I got an error “Out of Memory”, I checked my limits and I had 256MB at my disposal. This had me stumped for a while as all I could find about this error was about how I need to increase my memory limit but this was not the case. Eventually I came across one comment on one blog with the solution; because my server is VPS I need to disable the “Memory Usage Restrictions”.
I needed to edit my apache config file:


nano /etc/httpd/conf/http.conf

and disable the restriction by the commenting out the first two restrictions:


#RLimitMEM 89478485
#RLimitCPU 240

Then restart apache

httpd restart

This fixed the issue for me.

Posted in Apache | 3 Comments
Feb
25
2012

Australia Post API with PHP

This is a quick post to show people how to use the Australia Post API with PHP, I had a hard time getting this working as the documentation is good but very verbose and there are not too many examples for PHP out there. Anyway its fairly simple once you know how.

Requirements

First I would recommend doing this in OOP style so I will start by creating a class and adding two instance variables.

class Shipping
{
	private $api = 'https://auspost.com.au/api/';
	private $auth_key = 'XXXXXXXXXXXXXXXXX';
}

The First is the BASE url to the API and the second is the API Key you obtained from Australia Post, replace the X’s with your key.

Next we will create a method for fetching data from the API.

class Shipping
{
	private $api = 'https://auspost.com.au/api/';
	private $auth_key = 'XXXXXXXXXXXXXXXXX';
 
        public function getRemoteData($url)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL,$url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
		  'Auth-Key: ' . $this->auth_key
		));
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$contents = curl_exec ($ch);
		curl_close ($ch);
		return json_decode($contents,true);
	}
}

This gets the remote data requested and returns it as an array of data.

We now should add some constants to our class for the limits that Australia Post enforces.

and a few methods for fetching the data.

class Shipping
{
	private $api = 'https://auspost.com.au/api/';
	private $auth_key = 'XXXXXXXXXXXXXXXXX';
        const MAX_HEIGHT = 35; //only applies if same as width
	const MAX_WIDTH = 35; //only applies if same as height
	const MAX_WEIGHT = 20; //kgs
	const MAX_LENGTH = 105; //cms
	const MAX_GIRTH = 140; //cms
	const MIN_GIRTH = 16; //cms
 
        public function getRemoteData($url)
	{
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL,$url);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
		  'Auth-Key: ' . $this->auth_key
		));
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$contents = curl_exec ($ch);
		curl_close ($ch);
		return json_decode($contents,true);
	}
 
        public function getShippingCost($data)
	{
		$edeliver_url = "{$this->api}postage/parcel/domestic/calculate.json";
		$edeliver_url = $this->arrayToUrl($edeliver_url,$data);		
		$results = $this->getRemoteData($edeliver_url);
 
		if (isset($results['error']))
			throw new Exception($results['error']['errorMessage']);
 
		return $results['postage_result']['total_cost'];
	}
 
        public function arrayToUrl($url,$array)
	{
		$first = true;
		foreach ($array as $key => $value)
		{
			$url .= $first ? '?' : '&';
			$url .= "{$key}={$value}";
			$first = false; 	
		}	
		return $url;
	}
 
        public function getGirth($height,$width)
	{
		return ($width+$height)*2;
	}
}

to get the cost of an item to be shipped by regular post:

        $shipping = new Shipping();
        $data = array(
		'from_postcode' => 4511,
		'to_postcode' => 4030,
		'weight' => 10,
		'height' => 105,
		'width' => 10,
		'length' => 10,
		'service_code' => 'AUS_PARCEL_REGULAR'
	);
        try{
	         echo $shipping->getShippingCost($data);
        }
        catch (Exception $e)
        {
                 echo "oops: ".$e->getMessage();
        }

There are a lot more things you can do with the API, here is a link to the documentation.

I hope this has helped someone in figuring out how to get the API functioning.

Posted in PHP | 8 Comments
Jan
22
2012

Yii with the Filemaker API

This is my first entry in my blog and I wish to start by sharing some code I wrote recently whilst integrating the Filemaker API into Yii. I started by looking in the Extensions section of the Yii main website to see if I could find anything that someone else had written but without success. I came to the realization that this had not been done yet or not created as an extension so I began on integrating it myself. The following are the steps I followed to get a functional Filemaker/Yii website working ( most likely not the best way but it works ).

  • I started by creating a vendors folder within the protected folder of my Yii site and imported the API.
  • I added an entry into config/main.php to automatically import the API.
    'import'=>array(
            'application.models.*',
    	'application.components.*',
    	'application.vendors.*',
    ),
  • I then added a few application-level parameters for connection to the API.
    'params'=>array(
    	'fm_host' => 'example.com',
    	'fm_file' => 'myfile.fp7',
    	'fm_user' => 'myusername',
    	'fm_pass' => 'mypass',
    ),
  • I decided that creating a new behaviour class would be the best approach since I can attach this to any class. So I created a CFilemakerBehaviour class and placed it within the components sections of the protected folder. Here are some basics of the class.
    class CFileMakerBehaviour extends CBehavior
    {
    	public $fm;
    	public $layout;
     
    	public function __construct($layout,$attributes = array())
    	{
    		$host = Yii::app()->params['fm_host'];
    		$file = Yii::app()->params['fm_file'];
    		$user = Yii::app()->params['fm_user'];
    		$pass = Yii::app()->params['fm_pass'];
     
    		$this->fm = new FileMaker($file,$host,$user,$pass);
     
    		$this->layout = $layout;
    	}	
    	//conditions requires an associative array i.e key => value
    	//if you want to add less than or greater than add it to the value i.e price => '> 15'
     
    	//gets all records for the layout
    	public function findAllRecords($conditions=array())
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    				$find_command->addFindCriterion($label,$value);
    		}
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			throw new FileMakerException($result->getMessage(),$result->getCode());
    		}
     
    		return $result->getRecords();
    	}
     
            //conditions requires an associative array i.e key => value
    	//if you want to add less than or greater than add it to the value i.e price => '> 15'
     
    	//gets a single record
            public function findRecord($conditions=array())
            {
                  $find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    			{
    				$find_command->addFindCriterion($label,$value);
    			}
    		}
     
    		$find_command->setRange(0,1);
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			return false;
    		}
    		return $result->getFirstRecord(); 
    	}
     
    	//gets the maximum value of a specific field
    	public function getFieldMaximum($field,$conditions=array())
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    			{
    				$find_command->addFindCriterion($label,$value);
    			}
    		}
     
    		$find_command->addSortRule($field,1,FILEMAKER_SORT_DESCEND);
    		$find_command->setRange(0,1);
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			return false;
    		}
    		$record = $result->getFirstRecord();
    		return $record->getField($field);
    	}
     
    	//gets the minimum value of a specific field
    	public function getFieldMinimum($field,$conditions=array())
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (FileMaker::isError($find_command)) {
    			throw new FileMakerException($find_command->getMessage(),$find_command->getCode());
    		}
     
    		if (count($conditions) > 0)
    		{
    			foreach ($conditions as $label => $value)
    			{
    				$find_command->addFindCriterion($label,$value);
    			}
    		}
     
    		$find_command->addSortRule($field,1,FILEMAKER_SORT_ASCEND);
    		$find_command->setRange(0,1);
    		$result = $find_command->execute();
    		if (FileMaker::isError($result))
    		{
    			return false;
    		}
    		$record = $result->getFirstRecord();
    		return $record->getField($field);
    	}
    }
     
    class CFileMakerException extends Exception
    {
     
    }
  • I also created a dataprovider class which is handy for cGridView:
    class CFileMakerProvider extends CDataProvider
    {
    	public $keyField;
    	private $fields;
    	private $result;
    	private $keys_array = array();
    	private $image_columns = array();
    	private $select = array();
    	private $where = array();
     
    	public function __construct($layout,$config = array())
    	{
    		$this->attachBehaviour('filemakerbehaviour',new FileMakerBehaviour($layout));
     
    		$this->fields = $this->layout->getFields();
     
    		foreach($config as $key=>$value)
    			$this->$key=$value;
    	}
     
    	protected function fetchData()
    	{	
    		$find_command = $this->fm->newFindCommand($this->layout);
     
    		if (count($this->where))
    		{
    			foreach ($this->where as $label => $value)
    				$find_command->addFindCriterion($label,$value);
    		}
     
    		if(($pagination=$this->getPagination())!==false)
    		{
    			$pagination->setItemCount($this->getTotalItemCount());
    			$find_command->setRange($pagination->getOffset(), $pagination->getLimit());
    			$this->result = $find_command->execute();
    			if (FileMaker::isError($this->result)) {
    				return 0;
    			}
    			return $this->convertRecordsToArray($this->result->getRecords());
    		}
    		else
    		{
    			$this->result = $find_command->execute();
    			if (FileMaker::isError($this->result)) {
    				return 0;
    			}
    			return $this->convertRecordsToArray($this->result->getRecords());
    		}
     
    	}
     
    	protected function convertRecordsToArray($records)
    	{
    		$data = array();
    		foreach ($records as $i => $record)
    		{
    			foreach ($this->fields as $field)
    			{
    				$field_name = $field->getName();
    				if (!count($this->select) || in_array($field_name,$this->select))
    				{
    					if (in_array($field_name,$this->image_columns))
    					{
    						$field_data = $record->getField($field_name);
    						if (!empty($field_data))
    						{
    							$raw_image = $this->fm->getContainerData($field_data);
    							if (preg_match('/\.(jpg|jpeg|JPG)/',$field_data))
    								$mime = 'image/jpeg';
    							if (preg_match('/\.png/',$field_data))
    								$mime = 'image/png';
    							if (preg_match('/\.gif/',$field_data))
    								$mime = 'image/gif';
     
    							if (isset($mime))
    							{
    								$data[$i][$field_name] = CHtml::image("data:{$mime};base64,".base64_encode($raw_image),'');
    							}
    							else
    							{
    								$data[$i][$field_name] = 'No Image.';
    							}
    						}
    						else
    						{
    							$data[$i][$field_name] = 'No Image.';
    						}
    					}
    					elseif (in_array($field_name,$this->doc_columns))
    					{
    						$field_data = $record->getField($field_name);
    						$data[$i][$field_name] = $record->getField($field_name);
    					}
    					else
    						$data[$i][$field_name] = $record->getField($field_name);
    				}
    			}
    			$this->keys_array[$i] = $record->getField($this->keyField);
    		}
    		return $data;
    	}
     
    	protected function fetchKeys()
    	{
    		return $this->keys_array;
    	}
     
    	protected function calculateTotalItemCount()
    	{
    		$find_command = $this->fm->newFindCommand($this->layout);
    		if (count($this->where))
    		{
    			foreach ($this->where as $label => $value)
    				$find_command->addFindCriterion($label,$value);
    		}
    		if(($pagination=$this->getPagination())!==false)
    			$find_command->setRange($pagination->getOffset(), $pagination->getLimit());
    		$this->result = $find_command->execute();
    		if (FileMaker::isError($this->result)) {
    			return 0;
    		}
    		return $this->result->getFoundSetCount();
    	}
    }
     
    class FileMakerProviderException extends Exception{}

To use the above classes I created models that extended the CFormModel then attached the CFileMakerBehaviour and manually loaded in what I needed.
Anyway these are the real basics and is only for a readonly website at the moment. I might create an extension later if I end up using this API more often (hopefully not).

Posted in Yii | Tagged , , | 2 Comments
Copyright © 2012 by damiandennis.com.
All Rights Reserved.