Problem: rendering barcodes in CodeIgniter via Zend library barcode.
I googled, and also tried all tutorials on first 2 pages. I stackoverflowed and found quiet a few topics on my problem, even few are marked as answered but no luck.
Finally I tried this https://stackoverflow.com/a/15480779/1564365 but yet another error message.
error:
Fatal error: Class 'Zend\Barcode\ObjectPluginManager' not found
that means it is actually loading Barcode library but with error.
sidenote: ZF 2.2 fresh download (today), CI 2.1.3 fresh download (today)
To solve this, I am forced to use ZF1.
step by step:
Download (Zend Framework 1.12.3 Full) from here
Unzip files and locate folder Zend in ./libraries folder copy it to CI application/libraries
Create new file inside (CI) application/libraries/Zend.php "loader for ZF"
with code as follows
<?php if (!defined('BASEPATH')) {exit('No direct script access allowed');}
/**
* Zend Framework Loader
*
* Put the 'Zend' folder (unpacked from the Zend Framework package, under 'Library')
* in CI installation's 'application/libraries' folder
* You can put it elsewhere but remember to alter the script accordingly
*
* Usage:
* 1) $this->load->library('zend', 'Zend/Package/Name');
* or
* 2) $this->load->library('zend');
* then $this->zend->load('Zend/Package/Name');
*
* * the second usage is useful for autoloading the Zend Framework library
* * Zend/Package/Name does not need the '.php' at the end
*/
class CI_Zend
{
/**
* Constructor
*
* #param string $class class name
*/
function __construct($class = NULL)
{
// include path for Zend Framework
// alter it accordingly if you have put the 'Zend' folder elsewhere
ini_set('include_path',
ini_get('include_path') . PATH_SEPARATOR . APPPATH . 'libraries');
if ($class)
{
require_once (string) $class . EXT;
log_message('debug', "Zend Class $class Loaded");
}
else
{
log_message('debug', "Zend Class Initialized");
}
}
/**
* Zend Class Loader
*
* #param string $class class name
*/
function load($class)
{
require_once (string) $class . EXT;
log_message('debug', "Zend Class $class Loaded");
}
}
and controllers method should be as follows
function barcode() {
$this->load->library('zend');
$this->zend->load('Zend/Barcode');
$test = Zend_Barcode::draw('ean8', 'image', array('text' => '1234565'), array());
var_dump($test);
imagejpeg($test, 'barcode.jpg', 100);
}
Related
I was wondering if there is a way to load different folder based on php version. I could do it writing my own autoloader, but i was wondering if there is a way of using composer for that?
Ps. I have seen this in use before in module / plugin application that where redistributed globally to work with wide range of env. Those scripts where using own autoloading classes.
I am curios is there a way to use composer in similar way.
Scenario: class / folder structure:
class >
php5.6 >
- SomeClass.php
...
php7.x >
- SomeClass.php
...
php8.x >
- SomeClass.php
...
Compare php version and do something:
$classPathForAutoloader = '';
if (version_compare(PHP_VERSION, '8.0.0') >= 0) {
$classPathForAutoloader = 'php8.x';
// do something to composer autoload or
// use declaration
}else if(version_compare(PHP_VERSION, '7.0.0') >= 0){
$classPathForAutoloader = 'php7.x';
// do something to composer autoload or
// use declaration
}else if(version_compare(PHP_VERSION, '5.6.0') >= 0{
$classPathForAutoloader = 'php5.6';
// do something to composer autoload or
// use declaration
}else{
// throw Exception ...
}
standard composer setup:
{
"name": "some/name",
"require": {
},
"authors": [
{
"name": "Some Name",
"email": "some#email.com"
}
],
"autoload": {
"psr-4": {
"Devwl\\": "class/",
"Tools\\": "tools/"
},
"classmap": [
"class/"
],
"exclude-from-classmap": []
}
}
I don't think Composer provides a way to dynamically autoload different paths.
Can you use version_compare in a single SomeClass.php class only where the functionality differs by PHP version? Or write the entire SomeClass.php to be backwards compatible?
To me loading different classes depending on the PHP version is asking for trouble when it comes to reproducibility across environments.
Another option would be to use require_once to load the different classes, but for maintainability I'd really lean towards a single class with version checks only when absolutely necessary.
So i have created a class which does what I need. It can laso work alongside Composer autoloader.
<?php
class PhpVersionAutoloader{
private $baseClassesDirPath = null;
private $phpVersionArr = [];
private $phpDir = null;
private $classes = []; /** Keep a record of all loaded classes */
/**
* Allows to change base dir path.
* If not set the path will be set to file _DIR_
*
* #see $this->baseClassesDirPath
*
* #param string $path
* #return void
*/
public function setBaseClassesDirPath($path)
{
$this->baseClassesDirPath = $path;
}
/**
* Map available dir name and php version
*
* #see $this->phpVersionArr
*
* #param string $directory name
* #param string $phpVersion
* #return void
*/
public function registerPhpDir($dir, $phpVersion){
$this->phpVersionArr[] = [$dir => $phpVersion];
}
/**
* Compare curent php version with $this->phpVersionArr to determin the right path for class load
*/
public function selectPhpDir(){
foreach ($this->phpVersionArr as $key => $phpVDir) {
$this->position = $key;
foreach($phpVDir as $key => $value){
if (version_compare(PHP_VERSION, $value) >= 0){
$this->phpDir = $key;
break 2;
}
}
}
}
/**
* Register autloader
*
* #return void
*/
public function register(){
spl_autoload_register(function($className)
{
$namespace = str_replace("\\","/",__NAMESPACE__);
$className = str_replace("\\","/",$className);
$this->baseClassesDirPath = ($this->baseClassesDirPath === null) ? str_replace("\\","/",__DIR__) : $this->baseClassesDirPath;
$class = $this->baseClassesDirPath."/classes/".$this->phpDir.'/'. (empty($namespace)?"":$namespace."/")."{$className}.php";
$this->classes[] = $class;
if (file_exists($class)){
include_once($class);
}else{
// ... if not exsist try to load lower php version file?
// ... or throw new Error("Error Processing Request", 1);
}
});
}
}
Use the PhpVersionAutoloader object like this:
/**
* Use example
*/
$loader = new PhpVersionAutoloader(); // init PhpVersionAutoloader object
$loader->setBaseClassesDirPath('C:/xampp/htdocs/blog/blog autoloading'); // if not used will use _DIR_ to create path
$loader->registerPhpDir('php8.x', '8.0.0'); // as "folder name" => "php version"
$loader->registerPhpDir('php7.x', '7.0.0'); // ...
$loader->registerPhpDir('php5.6', '5.6.0'); // ...
$loader->selectPhpDir(); // compare system php version and selects the correct phpX.X subfolder
$loader->register(); // register autoloader
I also created more functional class of this loader which allow to force specific directory to load from or even allow to load classes from older version of PHP if not found in selected version.
See github [here]
I have a multiple language website I want to create a specific cache folder for every language. How Can I do this?
I currently using one cache folder with this code.
Can You Help Me?
$lang = $CI->session->userdata('language');
$cache_path .= md5($uri).'-'.$lang;
the parameter that configures the cache folder is in config.php and its called cache_path. For modifying in during runtime, we can use the $this->config->set_item function. Obviously, the cache folder switch should be done as early as possible in the controller function, before the caching function call.
Here is a sample implementation, controller Test:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Test extends CI_Controller {
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* #see https://codeigniter.com/user_guide/general/urls.html
*/
public function index()
{
$user_language = 'french';
$this->config->set_item('cache_path', 'IS_ROOT/cache/' . $user_language . '/');
$this->output->cache(1);
$this->load->view('welcome_message');
}
}
when you run it, you can see in the logs, that the directory "french" under the "global" IS_ROOT/cache was used:
INFO - 2018-06-09 22:12:39 --> File loaded: /php_basedir/CodeIgniter_3_1_8/application/views/welcome_message.php
DEBUG - 2018-06-09 22:12:39 --> Cache file written: IS_ROOT/cache/french/bc3ad60292ed776397da07cac67ddd28
INFO - 2018-06-09 22:12:39 --> Final output sent to browser
DEBUG - 2018-06-09 22:12:39 --> Total execution time: 0.0138
hope it helps
I Find a solution. we must edit output.php in core folder like this.
public function _write_cache($output){
$CI =& get_instance();
$lang = $CI->session->userdata('language');
$path = $CI->config->item('cache_path');
$cache_path = ($path === '') ? APPPATH.'cache_'.$lang.'/' : $path;
//other code
}
public function _display_cache(&$CFG, &$URI){
$CI =& get_instance();
$lang = $CI->session->userdata('language');
$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache_'.$lang.'/' : $CFG->item('cache_path');
//other code
}
Codeigniter does not find trivial classes:
Unable to load the requested class: Bcrypt
But the same goes for custom made classes defined in files in application/libraries/. I am used that django lists the folders where it searched for a file, but did not find one. Obviously CI must also iterate over some list of folders or files, but is not as polite to display them along with the error.
It seems as if CI has a naming convention to deduce the (set of) filename(s) where it would expect a class to be. How can I programmatically error_log the list of folders or filenames that Codeigniter or PHP tried to track down this class?
EDIT: The lines of code that produce such a loading-error are:
$autoload['libraries'] = array('database','session','mi_file_fetcher');
in application/config/autoload.php and
$this->load->library("bcrypt");
in application/models/User.php
As stated in the comments, I was not asking for a fix, I was asking for a list.
I managed to do so by updating system/core/Loader.php
protected function _ci_load_library_files_tried($class, $subdir, $params, $object_name)
{
$files_tried = array(BASEPATH . 'libraries/' . $subdir . $class . '.php');
foreach ($this->_ci_library_paths as $path) {
if ($path === BASEPATH) {
continue;
}
array_push($files_tried, $path . 'libraries/' . $subdir . $class . '.php');
}
return $files_tried;
}
protected function _ci_load_library($class, $params = NULL, $object_name = NULL)
{
// ...
// If we got this far we were unable to find the requested class.
$files_tried = $this->_ci_load_library_files_tried($class, $subdir, $params, $object_name);
log_message('error', 'Unable to load the requested class: '.$class .
", tried these files:\n" . join("\n", $files_tried));
show_error('Unable to load the requested class: '.$class .
', tried these files:<ul><li>' . join('</li><li>', $files_tried) . '</li></ul>');
}
Would be great if CI actually provided decent debugging information.
The CodeIgniter (CI) documentation does tell you the default locations of libraries, models, helpers, views and many other framework objects. There isn't a section that explicitly lists the folders though. The Loader Class documentation does tell you, but you have to dig for it a bit.
The subtopics on the General Topics section of the docs clearly state the default locations for the various classes the frameworks uses and where to put custom classes.
In most cases following the prescribed file structure and using the loader class, e.g. (Bcrypt.php is in /application/libraries/)
$this->load->library('bcrypt');
works perfectly.
There are cases (none of which seem to be involved in your problem) where CI needs help. Rather than hack or extend CI_Loader an autoloader is useful in these cases.
There are lots of ways to add an autoloader but my preference is to use CI's Hooks feature. Here's how.
In config.php set 'enable_hooks' to TRUE
$config['enable_hooks'] = TRUE;
These lines go in /application/config/hooks.php
$hook['pre_system'][] = array(
'class' => '',
'function' => 'register_autoloader',
'filename' => 'Auto_load.php',
'filepath' => 'hooks'
);
The following is the contents of /application/hooks/Auto_load.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
function register_autoloader()
{
spl_autoload_register('my_autoloader');
}
/**
* Allows classes that do not start with CI_ and that are
* stored in these subdirectories of `APPPATH`
* (default APPPATH = "application/" and is defined in "index.php")
* libraries,
* models,
* core
* controllers
* to be instantiated when needed.
* #param string $class Class name to check for
* #return void
*/
function my_autoloader($class)
{
if(strpos($class, 'CI_') !== 0)
{
if(file_exists($file = APPPATH.'libraries/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'models/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'core/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'controllers/'.$class.'.php'))
{
require_once $file;
}
}
}
The function log_message($level, $message) could be used in the above if you wanted.
If you are using some other creative folder structure you will have to modify the above to accommodate that layout.
I am having problems getting my sparks install to work with my codeigniter install
here are the steps I took which were as follows:
I went to my root of my codeigniter project folder through my PHPCLI to install sparks using the below command
php -r "$(curl -fsSL http://getsparks.org/go-sparks)"
i installed the active record library using the spark command below
php tools\spark install -v0.0.2 php-activerecord
2a. this command gave me the follwing folder structure
-application
-sparks
-php-activerecord
-0.0.2
-config
-variables
-vendor
-system
-tests
-tools
-lib
-spark
-sparktypes
-test
-user_guide
2b. this command generates a sparks containing php active record folder that makeup the necessary components of php-activerecord, the command using generates a MY_Loader.php file which looks like this
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Sparks
*
* An open source application development framework for PHP 5.1.6 or newer
*
* #package CodeIgniter
* #author CodeIgniter Reactor Dev Team
* #author Kenny Katzgrau <katzgrau#gmail.com>
* #since CodeIgniter Version 1.0
* #filesource
*/
/**
* Loader Class
*
* Loads views and files
*
* #package CodeIgniter
* #subpackage Libraries
* #author CodeIgniter Reactor Dev Team
* #author Kenny Katzgrau <katzgrau#gmail.com>
* #category Loader
* #link http://codeigniter.com/user_guide/libraries/loader.html
*/
class MY_Loader extends CI_Loader
{
/**
* Keep track of which sparks are loaded. This will come in handy for being
* speedy about loading files later.
*
* #var array
*/
var $_ci_loaded_sparks = array();
/**
* Is this version less than CI 2.1.0? If so, accomodate
* #bubbafoley's world-destroying change at: http://bit.ly/sIqR7H
* #var bool
*/
var $_is_lt_210 = false;
/**
* Constructor. Define SPARKPATH if it doesn't exist, initialize parent
*/
function __construct()
{
if(!defined('SPARKPATH'))
{
define('SPARKPATH', 'sparks/');
}
$this->_is_lt_210 = (is_callable(array('CI_Loader', 'ci_autoloader'))
|| is_callable(array('CI_Loader', '_ci_autoloader')));
parent::__construct();
}
/**
* To accomodate CI 2.1.0, we override the initialize() method instead of
* the ci_autoloader() method. Once sparks is integrated into CI, we
* can avoid the awkward version-specific logic.
* #return Loader
*/
function initialize()
{
parent::initialize();
if(!$this->_is_lt_210)
{
$this->ci_autoloader();
}
return $this;
}
/**
* Load a spark by it's path within the sparks directory defined by
* SPARKPATH, such as 'markdown/1.0'
* #param string $spark The spark path withint he sparks directory
* #param <type> $autoload An optional array of items to autoload
* in the format of:
* array (
* 'helper' => array('somehelper')
* )
* #return <type>
*/
function spark($spark, $autoload = array())
{
if(is_array($spark))
{
foreach($spark as $s)
{
$this->spark($s);
}
}
$spark = ltrim($spark, '/');
$spark = rtrim($spark, '/');
$spark_path = SPARKPATH . $spark . '/';
$parts = explode('/', $spark);
$spark_slug = strtolower($parts[0]);
# If we've already loaded this spark, bail
if(array_key_exists($spark_slug, $this->_ci_loaded_sparks))
{
return true;
}
# Check that it exists. CI Doesn't check package existence by itself
if(!file_exists($spark_path))
{
show_error("Cannot find spark path at $spark_path");
}
if(count($parts) == 2)
{
$this->_ci_loaded_sparks[$spark_slug] = $spark;
}
$this->add_package_path($spark_path);
foreach($autoload as $type => $read)
{
if($type == 'library')
$this->library($read);
elseif($type == 'model')
$this->model($read);
elseif($type == 'config')
$this->config($read);
elseif($type == 'helper')
$this->helper($read);
elseif($type == 'view')
$this->view($read);
else
show_error ("Could not autoload object of type '$type' ($read) for spark $spark");
}
// Looks for a spark's specific autoloader
$this->ci_autoloader($spark_path);
return true;
}
/**
* Pre-CI 2.0.3 method for backward compatility.
*
* #param null $basepath
* #return void
*/
function _ci_autoloader($basepath = NULL)
{
$this->ci_autoloader($basepath);
}
/**
* Specific Autoloader (99% ripped from the parent)
*
* The config/autoload.php file contains an array that permits sub-systems,
* libraries, and helpers to be loaded automatically.
*
* #param array|null $basepath
* #return void
*/
function ci_autoloader($basepath = NULL)
{
if($basepath !== NULL)
{
$autoload_path = $basepath.'config/autoload'.EXT;
}
else
{
$autoload_path = APPPATH.'config/autoload'.EXT;
}
if(! file_exists($autoload_path))
{
return FALSE;
}
include($autoload_path);
if ( ! isset($autoload))
{
return FALSE;
}
if($this->_is_lt_210 || $basepath !== NULL)
{
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
}
// Autoload sparks
if (isset($autoload['sparks']))
{
foreach ($autoload['sparks'] as $spark)
{
$this->spark($spark);
}
}
if($this->_is_lt_210 || $basepath !== NULL)
{
if (isset($autoload['config']))
{
// Load any custom config file
if (count($autoload['config']) > 0)
{
$CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
}
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) AND count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// A little tweak to remain backward compatible
// The $autoload['core'] item was deprecated
if ( ! isset($autoload['libraries']) AND isset($autoload['core']))
{
$autoload['libraries'] = $autoload['core'];
}
// Load libraries
if (isset($autoload['libraries']) AND count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
foreach ($autoload['libraries'] as $item)
{
$this->library($item);
}
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
}
}
}
i modify my autoload.php to include php active record as below
$autoload['sparks'] = array('php-activerecord/0.0.2');
when i run my codeigniter site i get the following error
A PHP Error was encountered
Severity: Notice
Message: Use of undefined constant EXT - assumed 'EXT'
Filename: core/MY_Loader.php
Line Number: 174
Backtrace:
File: C:\xampp\htdocs\orm\application\core\MY_Loader.php
Line: 174
Function: _exception_handler
File: C:\xampp\htdocs\orm\application\core\MY_Loader.php
Line: 154
Function: ci_autoloader
File: C:\xampp\htdocs\orm\application\core\MY_Loader.php
Line: 67
Function: initialize
File: C:\xampp\htdocs\orm\index.php
Line: 274
Function: require_once
I am curious as to what could be causing this error? Please let me know if there is any other configuration that I am missing or if theres a mistake that I have made.
The EXT is defined in your root index.php file.
// The PHP file extension
// this global constant is deprecated.
define('EXT', '.php');
See if it's still there or not?
IN case that constant is not there, you can also define the autoload.php without using the constant.
I know this is an old post but hopefully this will save someone some time... I had the same issue and the above fix did not work. I finally fixed the issue in the htaccess file by removing the RewriteBase although I am not sure why this caused the issue in the first place.
just commented out the line as follows:
RewriteBase /
to
#RewriteBase /
I added one library for gettext translation. Added corresponding po and mo files.
And the translation is working fine.
Now when I update my po file, change some translation.. after that when I reload the page, I am getting the old translation, not the new.
Here is the Library code:
/**
* This method overides the original load method. Its duty is loading the domain files by config or by default internal settings.
*
*/
function load_gettext($userlang = false) {
/* I want the super object */
if ($userlang)
$this->gettext_language = $userlang;
else
$this->gettext_language = 'it_IT';
log_message('debug', 'Gettext Class gettext_language was set by parameter:' . $this->gettext_language);
putenv("LANG=$this->gettext_language");
setlocale(LC_ALL, $this->gettext_language);
/* Let's set the path of .po files */
$this->gettext_path = APPPATH . 'language/locale';
log_message('debug', 'Gettext Class path chosen is: ' . $this->gettext_path);
bindtextdomain($this->gettext_domain, $this->gettext_path);
textdomain($this->gettext_domain);
log_message('debug', 'Gettext Class the domain chosen is: ' . $this->gettext_domain);
return true;
}
/**
* Plural forms added by Tchinkatchuk
* http://www.codeigniter.com/forums/viewthread/2168/
*/
/**
* The translator method
*
* #param string $original the original string to translate
* #param array $aParams the plural parameters
* #return the string translated
*/
function _trans($original, $aParams = false) {
if (isset($aParams['plural']) && isset($aParams['count'])) {
$sTranslate = ngettext($original, $aParams['plural'], $aParams['count']);
$sTranslate = $this->replaceDynamically($sTranslate, $aParams);
} else {
$sTranslate = gettext($original);
if (is_array($aParams) && count($aParams))
$sTranslate = $this->replaceDynamically($sTranslate, $aParams);
}
return $sTranslate;
}
This is the usage in a controller:
$this->pos_language->load_gettext('fr_FR');
echo $this->pos_language->_trans('Hello world, good morning');
I think you need to compile your .po files to .mo files. Gettext uses the .mo file, the .po is just a human readable form.
If you haven't done the compilation step, your application is still reading your old .mo files, with the untranslated strings...
This page has some more info about gettext translation: http://wiki.creativecommons.org/Translating_PO_Files
I wrote a helper to integrate php-gettext with Smarty & Code Igniter 2
http://bit.ly/rrITVx
I hope it might help