Showing posts with label php. Show all posts
Showing posts with label php. Show all posts

Monday, 10 February 2014

How to use PHP Excel without php built in zip archive

"Fatal error: Class 'ZIPARCHIVE' not found"

I found myself in in the situation that I had to use PHPExcel to generate some graphs. Sounds easy enough, and it kind of is, but... after I develop locally on my machine running php 5.3 I face myself with the challenge that I have to install the code on a machine running php 5.1.2 (not suported by PHPExcel). I soon found out that the main problem is the fact that php 5.1 dose not have ZipArchive or PHPExcel_Shared_ZipArchive, you can install them but with a lot of headache and a lot of trying (more than 1 solutions available for more than 1 case) and to be honest, that solution was not the proper way to do it as this was a production server with a lot of stuff on it (you don't want to mess it up).
Maybe a guru server admin could find a proper solution, but I am not that, I am a dev, so... I started researching to find a way to change to another lib that works on 5.1. And so I found... nothing!!! (at least after 2-3h of research and reading a lot of useless forum posts).
As my search was not fruitful and time consuming and annoying I moved my atention to something I love but not like doing: hacking the code ( hacking the code of a maintained lib is not encouraged as this may lead to rough upgrades with lots of diffs etc.  ).
After a little more research and documentation I found pclzip as a php standalone lib here and I found that PHPExcel has a very simple way of changing the ziping class in the settings.
So this is what I have done:

  1. imported the pclzip lib
  2. created a wrapper class for compatibility reasons (pclzip dose not have the function names implemented in the other to libs)
  3. added my wrapper class as a ziping method in settings.php
  4. forced PHPExcel to use my class for ziping
NOTICE: This was tested only for writing, so I have no ideea what will happen when reading, but that is the subject of another post.

Here is a short description of the code I created:

################################################
// pclzip.extended.php
################################################

include('pclzip.lib.php');  // PhpConcept Library - Zip Module 2.8.2 -  http://www.phpconcept.net
class PCLZipExtended{
 // just a place holder
 function PCLZipExtended(){
  
 }
 
 private $zip;
 private $temp_dir;
 // implementation of function open
 // this function needs to create the zip file
 // pclzip dose not create the file untill any action is taken (create/append)
 function open($pFilename,$zipCreate){
  $this->zip = new PclZip($pFilename);
  $this->zip->create(array());
  
  return file_exists($pFilename);
 }
 // implementation of addFromString function
 // needs to save the string to a local file and then append it to the archive
 // keeping the paths is a ***ch
 function addFromString($_location,$data){
  $location=$this->tempdir().$_location;
  if(!file_exists(dirname($location)))
   mkdir(dirname($location), 0777, true);
  file_put_contents($location,$data);
  $loc_to_add = explode('/',$location);
  array_shift ($loc_to_add);
  array_pop ($loc_to_add);
  $loc_to_add = implode('/',$loc_to_add);
  $this->zip->add($location,$loc_to_add,dirname($location));
 }
 // we are done and we can clean up after our selfs 
 function close(){
  
  // do cleanup
  $this->rrmdir($this->tempdir());
 }
 // generate a temp dir to store the files needed for the zip
 // or if we already done this return it
 // and yes php 5.1 dose not have sys_get_temp_dir
 private function tempdir($dir='') {
  if(isset($temp_dir)) return $temp_dir;
  $tempfile=tempnam($dir,'');
  if (file_exists($tempfile)) { unlink($tempfile); }
  mkdir($tempfile);
  if (is_dir($tempfile)) { return $temp_dir=$tempfile.'/'; }
  return false;
 }
 // recursive delete for php
 private function rrmdir($dir='') {
  if (is_dir($dir)) {
   $objects = scandir($dir);
   foreach ($objects as $object) {
    if ($object != "." && $object != "..") {
     if (filetype($dir."/".$object) == "dir") rmdir($dir."/".$object); else unlink($dir."/".$object);
    }
   }
   reset($objects);
   rmdir($dir);
  }
 }
 
}

################################################
// PHPExcel: PHPExcel/PHPExcel/Settings.php
################################################

################

    const PCLZIP        = 'PHPExcel_Shared_ZipArchive';
// line: 42 added just this
    const PCLZIP_SOURCE = 'PCLZipExtended';
// line: 42 added just this
    const ZIPARCHIVE    = 'ZipArchive';

################


        if (($zipClass === self::PCLZIP) ||
// line: 120 added just this
            ($zipClass === self::PCLZIP_SOURCE) ||
// line: 120 added just this
            ($zipClass === self::ZIPARCHIVE)) {

################

################################################
// Main php file that dose all the work
################################################

        include('modules/ER_Reports/pclzip.extended.php');
        include('modules/ER_Reports/PHPExcel/PHPExcel.php');
        PHPExcel_Settings::setZipClass(PHPExcel_Settings::PCLZIP_SOURCE);
        $er = new ER_Reports();


And that's all folks!!!!

Wednesday, 3 October 2012

Thebuggenie:Development:Events:List

ATM Thebuggenie documentation is very low on details so I will post here a list of events I found in the source files of v 3.2

'core', 'rolepermissionsedit', $role
'core', 'setting_returnfromlogin'
'core', 'setting_returnfromlogout'
'core', 'project_sidebar_links_dashboard'
'core', 'project_sidebar_links_releases'
'core', 'project_sidebar_links_milestone'
'core', 'project_sidebar_links_roadmap'
'core', 'project_sidebar_links_team'
'core', 'project_sidebar_links_statistics'
'core', 'project_sidebar_links_timeline'
'core', 'config_project_tabs'
'core', 'project_dashboard_top'
'core', 'project_dashboard_bottom'
'core', 'project_header_buttons'
'core', 'project/projectinfo', $project
'core', 'config_project_panes'
'core', 'project_overview_item_links'
'publish', 'fixture_article_loaded'
'vcs_integration', 'new_commit'
'core', 'quicksearch_dropdown_firstitems'
'core', 'quicksearch_dropdown_founditems'
'core', 'reportissue.prefile'
'core', 'reportissue.listfields'

Monday, 16 January 2012

Sugarcrm custom chart

Creating a sugar chart dashlet is done the same way as you would create a simple dashlet, just extending 2 functions, for this reason I will not cover the way a sugar dashlet is created. Notes: The dashlets will be named  "CustomLineDashlet" and "CustomPieDashlet" and the module is "abc_Sample". You can use the predefined sugar chart definitions for parsing data (modules\Charts\chartdefs.php) or you can create your own to meet any custom demands. This is done by editing(creating if dose not exist) "custom\Charts\chartDefs.ext.php". For CustomPieDashlet : custom\Charts\chartDefs.ext.php:
$chartDefs['custom_pie_chart'] = array('type' => 'code',
 'id' => 'custom_pie_chart',
 'label' => 'custom_pie_chart label',
 'chartUnits' => 'The unit definition',
 'chartType' => 'pie chart',
 // important value that will be used to group the data
 'groupBy' => array( 'name' ), 
 'base_url'=> 
  array(  'module' => 'abc_Sample',
   'action' => 'index',
   'query' => 'true',
   'searchFormTab' => 'advanced_search',
   )   
);
custom\modules\abc_Sample\Dashlets\CustomPieDashlet\CustomPieDashlet.php
....
public function display() {
 $currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol'];
 require ("modules/Charts/chartdefs.php");
 // here we load the chart definition (custom\Charts\chartDefs.ext.php)
 $chartDef = $chartDefs['custom_pie_chart'];
 require_once ('include/SugarCharts/SugarChart.php');
 $sugarChart = new SugarChart();
 $sugarChart -> setProperties('', translate('LBL_OPP_SIZE', 'Charts') . ' ' . currency_symbol . '1' . translate('LBL_OPP_THOUSANDS', 'Charts'), $chartDef['chartType']);
 $sugarChart -> base_url = $chartDef['base_url'];
 $sugarChart -> group_by = $chartDef['groupBy'];
 $sugarChart -> url_params = array();
 $sugarChart -> getData($this -> constructQuery());
 $xmlFile = $sugarChart -> getXMLFileName($this -> id);
 $sugarChart -> saveXMLFile($xmlFile, $sugarChart -> generateXML());
 return $this -> getTitle('
') . '
' . $sugarChart -> display($this -> id, $xmlFile, '100%', '480', false) . '
'; } protected function constructQuery() { // this is the query used to get data and create the xml // for pie chart we have a simple query $query = " SELECT count(*) as total, name FROM table GROUP BY name ORDER BY name"; return $query; }
For CustomLineDashlet : custom\Charts\chartDefs.ext.php:
$chartDefs['custom_line_chart'] = array(  'type' => 'code',
 'id' => 'custom_line_chart',
 'label' => 'custom_line_chart label',
 'chartUnits' => 'The unit definition',
 'chartType' => 'line chart',
 // the legend will be the name and the x intervals will be the date
 'groupBy' => array( 'date','name' ), 
 'base_url'=> 
  array(  'module' => 'sam_Sample',
   'action' => 'index',
   'query' => 'true',
   'searchFormTab' => 'advanced_search'
 )   
);
custom\modules\abc_Sample\Dashlets\CustomLineDashlet\CustomLineDashlet.php
....
public function display() {
 $currency_symbol = $GLOBALS['sugar_config']['default_currency_symbol'];
 require ("modules/Charts/chartdefs.php");
 // here we load the chart definition (custom\Charts\chartDefs.ext.php)
 $chartDef = $chartDefs['custom_line_chart'];
 require_once ('include/SugarCharts/SugarChart.php');
 $sugarChart = new SugarChart();
 $sugarChart -> setProperties('', translate('LBL_OPP_SIZE', 'Charts') . ' ' . currency_symbol . '1' . translate('LBL_OPP_THOUSANDS', 'Charts'), $chartDef['chartType']);
 $sugarChart -> base_url = $chartDef['base_url'];
 $sugarChart -> group_by = $chartDef['groupBy'];
 $sugarChart -> url_params = array();
 $sugarChart -> getData($this -> constructQuery());
 $xmlFile = $sugarChart -> getXMLFileName($this -> id);
 $sugarChart -> saveXMLFile($xmlFile, $sugarChart -> generateXML());
 return $this -> getTitle('
') . '
' . $sugarChart -> display($this -> id, $xmlFile, '100%', '480', false) . '
'; } protected function constructQuery() { // this is the query used to get data and create the xml // for pie chart we have a simple query $query = " SELECT count(*) as total, name, date FROM table GROUP BY date,name ORDER BY name"; return $query; }
the meta files ( custom\modules\abc_Sample\Dashlets\CustomLineDashlet\CustomPieDashlet.meta.php and custom\modules\abc_Sample\Dashlets\CustomLineDashlet\CustomLineDashlet.meta.php) will look like this:
$dashletMeta['CustomSamplePieCart'] = array('module'  => 'abc_Sample',
            'title'       => 'Custom Pie Chart', 
                                          'description' => 'Custom description',
                                          'icon'        => 'themes/default/images/icon_sam_Sample_32.gif',
                                          'category'    => 'Charts');
and
$dashletMeta['CustomSampleLineCart'] = array('module'  => 'abc_Sample',
            'title'       => 'Custom Chart', 
                                          'description' => 'Custom description',
                                          'icon'        => 'themes/default/images/icon_sam_Sample_32.gif',
                                          'category'    => 'Charts');


Notes:
custom\Charts\chartDefs.ext.php is the place where you will define your chart type, important fields:
'groupBy' => array( 'date','name' ) (the x and legend fields)
'chartType' => 'line chart', (the swf name, php will capitalize and add .swf, so it will be lineChar.swf)

in the sql your x values will have to coincide (be the same) for all lines