Category Archives: PHP

Whats going to change when I update PHP on IBM i. PHPinfo is a clue

e Here’s a great little script to see whats going to change when you update PHP on IBM i.  It compares the phpinfo from your production site to your new instance of PHP.  This way you can scroll down and take note of specific differences to PHP.  This isn’t all the changes so there’s more to check but can get you pretty far.

 

https://github.com/brettalton/phpinfo-compare

There is an issue with library lists if your using the PDO_IBM driver.

https://bugs.php.net/bug.php?id=73785

Disable Z-Ray on PHP on IBM i
Edit the file /usr/local/zendphp7/etc/conf.d/zray.ini and change zray.enable=1 to zray.enable=0

; Enable Z-Ray
; zray.enable=1
zray.enable=0

Advertisements

Compiling PHP extensions on IBM i / PASE/ AIX

This is post for Andy Youens and anyone looking to compile PHP Extensions on IBM i.  The first thing i would do is get GCC on the IBM i by following Tony’s guide here: http://yips.idevcloud.com/wiki/index.php/PASE/GCC .  GCC is the compiler system that can take a PHP extension  source code, which are written in C, and compile it into an .SO file that can be added via PHP.ini.  In Andy’s case he want’s xdebug and you can get the latest source code here: http://xdebug.org/files/xdebug-2.3.3.tgz . Or find other versions here: http://xdebug.org/download.php .

Compile Script

Why can’t we just use any old binary? 

The source code has to be compiled to the processor and the operating system you’re running it on.  In the case of IBM i , the PASE environment is basically AIX (IBM’s flavor of UNIX) and it runs on IBM’s Power processor.

Binary compiled for PHP 7.1

https://github.com/phpdave/DataDump/raw/master/xdebug.so

 Further reading if you need more information to get strarted:

http://files.zend.com/help/Zend-Server-5.6-Cluster-Manager/content/compiling_php_extensions.htm

 

Automating Browser Testing with PHP and Selenium

Automated Browser Testing via PHP using Selenium and FB PHP-Webdriver

Automating your browser testing is very easy with using PHP and Selenium.  Below is a diagram of how it all works and the steps on how to achieve controlling your Browser with PHP!

Automating Browser Testing with PHP and Selenium

Automating Browser Testing with PHP and Selenium

Steps to install the basic components

  1. Install PHP on your machine download the PHP executable and set its path up in your environment (not sure how to do that?).
  2. Install Composer which will be used to download the source code for the facebook web driver
  3. Download the Selenium Standalone Server here http://www.seleniumhq.org/download/ (Direct link: selenium-server-standalone-2.53.1.jar)
  4. Run the selenium server by double clicking the jar file or invoking it from the command line..  You could also run this in your php script if you put the jar file in the same directory as the php script: exec(“java -jar “.__DIR__.”\selenium-server-standalone-2.53.1.jar”);
  5. Create a composer.json file https://gist.github.com/phpdave/580e5666c1d78d12e66e
  6. Run composer install using the composer.json file – This will download the facebook web driver
  7. Create an example PHP script on your computer.  https://github.com/facebook/php-webdriver/blob/community/example.php
  8. Run the script on the command line C:\myscripts\> php example.php
  9. This should start your browser up and start running the example script code.  You could then use the web driver to screen scrape, enter in various input and take various actions that are needed to test your application out.  You’ll also have the power of PHP to do various things such as save the results of your test to a file and all this is done in PHP!  So you don’t have to learn another language.  You’ll also want to get comfortable with firefox’s developers tools so you can inspect an element and get a unique selector for that element so you know how to interact with that element.

Note:

  • Supported Platforms: Windows, OSX, Linux.  Not supported on the IBMi.  This makes sense since browsers run on a users machine not on the i.  Therefore to automate you may have to setup a Linux VM on a server and have it called to test.  Or you can run the code on your local machine http://www.seleniumhq.org/about/platforms.jsp

Referencee
www.seleniumhq.org/download/

Adding PHP formatter to Selenium IDE firefox plugin to allow copying and pasting commands in PHP format

  1. Install the plugin here: https://addons.mozilla.org/en-US/firefox/addon/selenium-ide-php-formatters/
  2. In Selenium IDE go to Options->Clipboard Formatting-> PHP (PHPUnit)

This will give you output like this:

$this->open("/Page1/");
$this->type("name=field2", "99999");
$this->click("name=Submit");

which you’ll need to modify into this format if your using the PHP FB webdriver:

$driver->get("/Page1/");
$driver->findElement(WebDriverBy::name('field2'))->sendKeys("99999");
$driver->findElement(WebDriverBy::name('submit'))->click();

Adding a user extension to selenium IDE to add a new function

  1. Modify the user-extension.js that the selenium ide is using and add a function like this that will do an random email:
Selenium.prototype.doTypeRandomEmail = function(locator) {
    /**
    * Sets the value of an input field to a random email id,
    * as though you typed it in.
    *
    * @param locator an <a href="#locators">element locator</a>
    */

    // All locator-strategies are automatically handled by "findElement"
    var element = this.page().findElement(locator);

    /* The following block generates a random email string */
    var allowedChars = "abcdefghiklmnopqrstuvwxyz";
    var stringLength = 8;
    var randomstring = '';

    for (var i=0; i<stringLength; i++) {
        var rnum = Math.floor(Math.random() * allowedChars.length);
        randomstring += allowedChars.substring(rnum,rnum+1);
    }

    // Append a domain name
    randomstring += "@example.com"

    // Replace the element text with the new text
    this.browserbot.replaceText(element, randomstring);
};
  1. Then you can just call the function like this:
$this->typeRandomEmail("id=email");

Setting it up on an Amazon Linux EC2 instance

Follow this example to setup PHP on EC2 if you don’t already have a linux box to play with

Open the ports 7055 and 4444 on your EC2 server instance’s security group inbound rules

SSH into your Linux box run:

References: https://lambda-linux.io/blog/2015/01/28/announcing-firefox-browser-support-for-amazon-linux/

Testing DB2 prepare and execute select statements in IBM i Navigator to debug ZF2 ZFCUSER bug using a sql stored procedure

Have you ever wanted to run a prepare and execute select sql statement that you have in PHP in IBM i navigator’s “Run SQL”?

take for example this PHP:

This is how you can create the Album table and then create a stored procedure to test the SQL select prepared statement

Faster Alternatives to FTP for uploading files from Linux or Windows

FTP is great, but when your looking to send files quickly over the network you may want to look at the commands: scp, rcp, and pscp.  The use case scenario my friend Chuk brought up is the initial load of a project with many dependencies that were quickly retrieved from the internet but pushing to the hosting server is slower.  On a Mac or Linux box you just need to get to the terminal to use the command and on Windows you just need to use Putty.  The links below will show you how to use them:

Linux

SCP – Secure Copy

http://www.hypexr.org/linux_scp_help.php

RCP – Remote file copy

http://linux.about.com/od/commands/l/blcmdl1_rcp.htm

“-C option for compression should also be used to increase speed. The effect of compression, however, will only significantly increase speed if your connection is very slow. “

Windows to Linux

Download Putty

pscp – PuTTY Secure Copy

https://community.freescale.com/thread/220596

Other reasons for your file transfer being slow could be a slow connection to the server which if you can upgrade your connection, routers and internet connect to gigabit or better you’ll remove some of these issues

The “gotchas” of running Zend Framework 2 on older versions of Zend Server for IBM i – ZF2 skeleton Application

Have you tried the ZF2 skeleton Application on PHP on the IBM i and have run into issues getting it to work since your on ZS 5.5, 6.x and are unable to upgrade to ZS7 at the moment? Well here’s a few gotchas and things you’ll have to change to get it work correctly:


 

Fatal error: Can’t inherit abstract function Zend\Validator\Translator\TranslatorInterface::translate() (previously declared abstract in Zend\I18n\Translator\TranslatorInterface) in library/Zend/Mvc/I18n/Translator.php on line 19

1) Comment out the Translate method in i89n\Translator\TranslatorInterface.php

//public function translate($message, $textDomain = 'default', $locale = null);
//For some reason ZF2 has 2 methods with the same name but it works in newer versions of PHP

 

Zend\ServiceManager\Exception\ServiceNotFoundException

zendframework/library/Zend/ServiceManager/ServiceManager.php:529

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Zend\Db\Adapter\Adapter

2) set your config_glob_paths to the full path of the config/application.config.php. Note: the path below has to be specific to where your file is located on the IFS.

'config_glob_paths' => array(
      '/www/zendsvr/htdocs/zf2test/config/autoload/{,*.}{global,local}.php',
),
//AFter updating to ZS 7 you should be able to change this back to the relative path of config/autoload/{,*.}{global,local}.php

 

“album” in MYLIB type *FILE not found. SQLCODE=-204

3) Add ‘platform_options’ to your config/autoload/global.php

//The SQL that is generated by Zend's classes is putting quotes around the table like:
//SELECT 'album'.* FROM 'album'
//after turning off quote_identifiers it will run this SQL:
//SELECT album.* FROM album
return array(
     'db' => array(
         'driver'           => 'IbmDb2',
         'platform'         => 'IbmDb2',
         'platform_options' => array('quote_identifiers' => false),
         'database'         => '*LOCAL', // IBM i serial number or db directory entry name goes here
         'persistent' => true,
        'driver_options'    => array(
            'autocommit'     => DB2_AUTOCOMMIT_OFF, //::TODO:: We might not be able to use the constant since db2 may have not loaded at this point
            'i5_naming'     => DB2_I5_NAMING_ON, //::TODO:: We might not be able to use the constant since db2 may have not loaded at this point
            'i5_lib'        => 'MYLIB',
            'i5_libl'       => 'MYLIB MYLIB2 MYLIB3',
            ),
     ),
     'service_manager' => array(
         'factories' => array(
             'Zend\Db\Adapter\Adapter'
                     => 'Zend\Db\Adapter\AdapterServiceFactory',
         ),
     ),
 );

 

You’re view doesn’t display titles or artists

4) This is because the DB2 is case-insensitive and automatically converts lower-case column names that were created in the CREATE TABLE ALBUM script to upper-case columns (i.e. title is now TITLE and artist is now ARTIST). You can either modify the CREATE TABLE sql to force lower case column names by putting double quotes around your columns ( i.e. “title” “artist”). If you do it this way you’ll always have to put double quotes around it when using SQL, but in the PHP it won’t require double quotes. OR you can change the Album Model’s exchangeArray() to use the upper case column names. I recommend using the upper-case columns because the Zend\Db\Adapter\Driver\IbmDb2\ibmdb2 Statement class doesn’t know that it has to put double quotes around lowercase field names. The only approach with this is that you’ll have to change the field names to uppercase throughout the Getting Started Example

Solution 1

/* Creating table MYLIB.ALBUM */
DROP Table MYLIB.ALBUM;
CREATE TABLE MYLIB.ALBUM (
    'id' INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, NO ORDER, NO CYCLE, NO MINVALUE, NO MAXVALUE, CACHE 20) NOT HIDDEN ,
    'artist' VARCHAR (100) NOT NULL NOT HIDDEN ,
    'title' VARCHAR (100) NOT NULL NOT HIDDEN ,
    PRIMARY KEY ('id')
) NOT VOLATILE ;

LABEL ON TABLE MYLIB.ALBUM IS 'Test table for ZF2' ;

 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('The  Military  Wives',  'In  My  Dreams');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Adele',  '21');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Bruce  Springsteen',  'Wrecking Ball (Deluxe)');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Lana  Del  Rey',  'Born  To  Die');
 INSERT INTO MYLIB.ALBUM ('artist', 'title')
     VALUES  ('Gotye',  'Making  Mirrors');

GRANT SELECT,INSERT,UPDATE,DELETE ON MYLIB.ALBUM TO MYUSER;
SELECT * FROM MYLIB.ALBUM

Solution 2

<?php
namespace Album\Model;

 class Album
 {
     public $id;
     public $artist;
     public $title;

     public function exchangeArray($data)
     {
     //SOLUTION 2 - change the PHP file to use the upper-case column names
         $this->id     = (!empty($data['ID'])) ? $data['ID'] : null;
         $this->artist = (!empty($data['ARTIST'])) ? $data['ARTIST'] : null;
         $this->title  = (!empty($data['TITLE'])) ? $data['TITLE'] : null;
     }

	 public function getInputFilter()
     {
         if (!$this->inputFilter) {
             $inputFilter = new InputFilter();

             $inputFilter->add(array(
                 'name'     => 'ID',
                 'required' => true,
                 'filters'  => array(
                     array('name' => 'Int'),
                 ),
             ));

             $inputFilter->add(array(
                 'name'     => 'ARTIST',
                 'required' => true,
                 'filters'  => array(
                     array('name' => 'StripTags'),
                     array('name' => 'StringTrim'),
                 ),
                 'validators' => array(
                     array(
                         'name'    => 'StringLength',
                         'options' => array(
                             'encoding' => 'UTF-8',
                             'min'      => 1,
                             'max'      => 100,
                         ),
                     ),
                 ),
             ));

             $inputFilter->add(array(
                 'name'     => 'TITLE',
                 'required' => true,
                 'filters'  => array(
                     array('name' => 'StripTags'),
                     array('name' => 'StringTrim'),
                 ),
                 'validators' => array(
                     array(
                         'name'    => 'StringLength',
                         'options' => array(
                             'encoding' => 'UTF-8',
                             'min'      => 1,
                             'max'      => 100,
                         ),
                     ),
                 ),
             ));

             $this->inputFilter = $inputFilter;
         }

         return $this->inputFilter;
     }
 }

class AlbumForm extends Form
 {
     public function __construct($name = null)
     {
         // we want to ignore the name passed
         parent::__construct('album');

         $this->add(array(
             'name' => 'ID',
             'type' => 'Hidden',
         ));
         $this->add(array(
             'name' => 'TITLE',
             'type' => 'Text',
             'options' => array(
                 'label' => 'Title',
             ),
         ));
         $this->add(array(
             'name' => 'ARTIST',
             'type' => 'Text',
             'options' => array(
                 'label' => 'Artist',
             ),
         ));
         $this->add(array(
             'name' => 'submit',
             'type' => 'Submit',
             'attributes' => array(
                 'value' => 'Go',
                 'id' => 'submitbutton',
             ),
         ));
     }
 }

Fatal error: Can’t inherit abstract function Zend\Form\LabelAwareInterface::setLabel() (previously declared abstract in Zend\Form\ElementInterface) in /www/zendsvr/htdocs/zf2test/vendor/zendframework/zendframework/library/Zend/Form/Element.php on line 21

5) Comment out setlabel and getlabel in Zend/Form/View/LabelAwareInterface.php – https://github.com/zendframework/zf2/issues/5996

//public function setLabel($label);
    //public function getLabel();

Doctrine is not supported for the IBM DB2

This isn’t a ZF2 issue directly, but if you try and use ZF2 plugins such as ZFCuser you’ll run into issues. Doctrine doesn’t work that well with IBM DB2 currently. The current implementation is based on DB2 for Linux. There is talk about creating new classes that would handle the IBM DB2 specifically but there hasn’t been any work on it. A conversation looking into solving this is being had at – https://github.com/doctrine/dbal/pull/518 . Novice PHP programmers remember that there’s multiple ways of solving a problem and doctrine is not a must have to get the job done.

UPDATE on Case-sensitivity – Dec 3 2014

I think some of the case sensitivity issues can be fixed if Zend Framework’s Zend\Db\Adapter\Driver\IbmDb2\ibmdb2 is updated to use QSYS2.DELIMIT_NAME which is available in V7R1 TR 8 and V7R2. Also doctrine could be used if they used that feature. Not everyone is on that Version of the OS so this would need to be a feature that should be explicitly set. More info on QSYS2.DELIMIT_NAME – http://www.itjungle.com/fhg/fhg111214-story01.html