Showing posts with label Zend server. Show all posts
Showing posts with label Zend server. Show all posts

Friday, November 18, 2011

IBM DB2 extension has no limitation on number of opened persistent PHP DB2 connection.

To further study how to optimize PHP DB2 connection, I looked into PHP DB2 extension again recently. I want to find out the best way to use persist connection with considering about ODP reusing.

After reading the source code of PHP DB2 extension, I noticed that there is no limitation of maximum number of pconnection from PHP DB2 extension. In the C code, we can see only UserID, password, and Database name are used to compose hash code. You locate the place by search following code in the source code.

sprintf(hKey, "__db2_%s.%s.%s", uid, database, password);

This is interesting as it implies that I should avoid allowing huge number of different user profile to be used inside one Zend Server.

I am thinking that we will have difficult to reuse ODP when only userId, password, and database name are used to generate hash code for pconnect because ODP will be reused based on not only user name and password. For example, I think the ODP will be rebuilt if different requests use same User Name and password but different library list to get pconnection. PHP Db2 extension allows us to pass in library list. So, if developers, for some reason, happen to pass in different library list to run query on same library, the ODP will be rebuilt for sure.

Some other things I do not have answers are,

1) What happens to pconnection if its associated QSQSRVR job is terminated for some reason?

2) I saw something about ODBC version occur in C code. Does PHP DB2 extension works with ODBC in any way?

Sunday, August 28, 2011

install xdebug with Zend Server CE and Netbeans 7.0.x

Go to Fedora "Application -> System Tools -> Add/Remove Software" and make sure PHP PEAR and PHP PECL and XDebug are installed already. Then, run the following commands to add xdebug into Zend Server.

#  edit debugger.ini file to disable zend debugger.
#  ; register the extension to be loaded by Zend Extension Manager
# ;zend_extension_manager.dir.debugger=/usr/local/zend/lib/debugger
[root@jiaFedora14 yyjia]# sudo gedit /usr/local/zend/etc/conf.d/debugger.ini

#find where is xdebug.so
[root@jiaFedora14 /]# find /usr/ -name 'xdebug.so'
/usr/lib64/php/modules/xdebug.so

#  Make zend server to load xdegug.so before extension manager is loaded.
#  zend_extension=/usr/lib64/php/modules/xdebug.so
#  zend_extension=/usr/local/zend/lib/ZendExtensionManager.so
[root@jiaFedora14 yyjia]# sudo gedit /usr/local/zend/etc/conf.d/extension_manager.ini

# edit php.ini or other configuration files to have xdebug settings
# [xdebug]
# xdebug.remote_enable=on
# xdebug.remote_handler=dbgp
# xdebug.remote_mode=req
# ;xdebug.remote_connect_back=1
# xdebug.remote_host=192.168.1.190
# xdebug.remote_port=9001
# xdebug.idekey="netbeans-xdebug"
[root@jiaFedora14 yyjia]# sudo gedit /usr/local/zend/etc/php.ini

# Fedora has SELinux enabled by default. I open the port 9001.
[root@jiaFedora14 yyjia]# semanage port -a -t http_port_t -p tcp 9001

# restart Zend Server
[root@jiaFedora14 yyjia]# service zend-server restart

# check xdebug configuration.
[root@jiaFedora14 yyjia]# php -i | grep xdebug

After running all above command and see every thing is correct as expected, we do a simple configuration in Netbeans as shown in figure below,




Some notes:
1) The above steps only install xdebug for one developer. For a team developing environment, we need to install DBGp proxy.

2) I tried "xdebug.remote_connect_back=1" and hope I do not need to specify a fix hostname/ipaddress in php.ini. But, I failure on it. I have not dig deep into it.

Tuesday, March 22, 2011

Zend Server for IBM iSeries platform does not support multiple persistent connection to DB2

_
_
Edit: This post's content may only apply to i5/OS V5R4 without latest PTF. Please refer to comments for detailed info.

Persistent connection in PHP has its advantage and disadvantage. According to my observation about creating DB2 connection on i5/OS, time used to set up connection via normal connection and persistent connection can be 50 ~ 100 times different. However, persistent connection has its disadvantage as well. Some php programmer even call it evil. Also, it might not be worthy to take risk from persistent connection if the access traffic is not so high.

In a brief way to describe, the causer for persistent connection has disadvantage is that PHP itself is a stateless script language and database connection is usually stateful. That is, php script's life time only exists from the request coming and request end. Meanwhile, database connection will hold some state like table lock, user defined variables etc. So, the problem will occur when a php script use a persistent connection as a fresh new connection and it is not. PHP persistent does not support a kind of "private" connection, which will be used by one user session only. This kind private connection implementation can be found in easyComm i5 toolkit.

Back to what I observed recently. I find that Zend Server (ver 5.0.4) for IBM i5/OS V5R4 does not supports having multiple persistent connection in one request to php scripts. Below is a simple testing code. When you run it, you can see that the output Current Schema is not ALWAYS as what you specified in db2 connection string. I guess the hash function used Zend Server for resource manager may has some problem. Or, DB2 extension has a bug if it does not intend to support only one persistent connection in one PHP script request.

Change the db2_pconnect to db2_connect to see different output. You need to run this script many times to see that you can not ALWAYS get the right schema as your current schema. Most likely, you need to take 5 minutes to 10 minutes break during the testing and see the wrong result to come out.


<?php 

$sysStr = 'select CURRENT SCHEMA from SYSIBM.SYSDUMMY1 ';

$params = array(
 'username' => 'accountNameOne', 
 'password' => 'accountPwdOne',
 'dbname' => '*LOCAL', 
 'driver_options' => array('i5_lib' => 'libraryOne')
);
$connOne = db2_pconnect($params['dbname'], $params['username'], 
$params['password'], $params['driver_options']);
$sysStmt = db2_prepare($connOne, $sysStr);
db2_execute($sysStmt);
$returnObj = db2_fetch_object($sysStmt);
var_dump($returnObj);

$params2 = array(
 'username' => 'accountNameTwo', 
 'password' => 'accountPwdTwo', 
 'dbname' => '*LOCAL', 
 'driver_options' => array('i5_lib' => 'libraryTwo')
);
$connTwo = db2_pconnect($params2['dbname'], $params2['username'], 
$params2['password'], $params2['driver_options']);
$sysStmt2 = db2_prepare($connTwo, $sysStr);
db2_execute($sysStmt2);
$returnObj2 = db2_fetch_object($sysStmt2);
var_dump($returnObj2);

Sunday, March 13, 2011

install and configure Zend server Java Bridge on Linux

As far as I know, there are two active PHP-Java bridge projects. One is PHP/Java Bridge hosted on SourceForge. The other is Java bridge coming with Zend Server and Zend Server CE for linux and IBM i. It is clear that sourceForge PHP/Java bridge is based on SOAP web service. But, this make me feel it is not useful so much as it is not difficult for a PHP programmer to write SOAP client to call a SOAP service written in Java. I guess Zend Java bridge is implemented in client/server architecture too as its configuration parameters include a TCP/IP port number. I thought Zend Java Bridge is written based on JNI technology. However, it seems not true.

Anyway, the mystification of Zend Java Bridge attracts me to give it a shot. Here are simple steps about how to install and configure Zend Java Bridge.

1) Following post Installing Zend server CE on Fedora 14 and fix YUM update to install Zend Server CE on Fedora 14.

2) Running command yum search java-bridge to have output similar as below.

[root@jiaFedora14 yyjia]# yum search java-bridge
Loaded plugins: langpacks, presto, refresh-packagekit
Adding en_US to language list
updates/pkgtags | 56 kB 00:00
======================================================================== Matched: java-bridge =========================================================================
php-5.2-java-bridge-zend-server.x86_64 : Zend Java bridge
php-5.3-java-bridge-zend-server.x86_64 : Zend Java bridge
[root@jiaFedora14 yyjia]#


3) call command yum install php-5.3-java-bridge-zend-server to install Zend Java Bridge as I installed php 5.3 version on my machine.

4) call command /usr/local/zend/etc/rc.d/06jb stop and command /usr/local/zend/etc/rc.d/06jb start to start Zend Java Bridge if it is necessary. Or you can enable/disable Zend Java Bridge from Zend Server admin Web page.

5) compile following Java code into a .jar file, say jia.jar and add put it into directory /usr/local/zend/bin.

SystemPropertyList.java
package jia.blog.util.lang;

import java.util.Properties;

/**
 *
 * @author Yiyu Jia
 */
public class SystemPropertyList {

    public static Properties listSystemProperties(){
         return System.getProperties();
    }
}


6) open file /usr/local/zend/etc/watchdog-jb.ini and add jia.jar file into the CLASSPATH.

7) put below PHP code into directory, where Zend server executes php file. For example, /var/www/html.

javaInfo.php
<?php
$javaEnv = new Java("jia.blog.util.lang.SystemPropertyList");
$out = $javaEnv->listSystemProperties();
?>

List of JVM System Properties

<?php foreach($out as $key => $value) { ?> <?php } ?>
<?php echo $key; ?> <?php echo $value; ?>

8) open web browser and access php code, for example http://localhost/javaEnv.php. If you can see the list of Java system properties, it is done. Enjoy it. This Java system properties is very important for Java programmer to create java app running in Zend Java Bridge.

Note: it seems that Zend Java Bridge does not support Java class hot deployment. So, you may need to restart Java Bridge every time after you modified your java classes.

Sunday, March 6, 2011

Installing Zend server CE on Fedora 14 and fix YUM update

Install Zend Server CE on Fedora 14 (SElinux diabled) is pretty easy. Here are key steps,

1) With root account privilege, go to directory /etc/yum.repos.d and create a file named as anyName.repo. The content of file is as below,


[Zend]
name=Zend Server
baseurl=http://repos.zend.com/zend-server/rpm/$basearch
enabled=1
gpgcheck=0

[Zend_noarch]
name=Zend Server - noarch
baseurl=http://repos.zend.com/zend-server/rpm/noarch
enabled=1
gpgcheck=0


2) With root privilege, running below command,
yum install zend-server-php-5.3

3) After running step 2, Zend server is installed. However, you may run into error when you run yum update. The error message is as below,

Fatal Python error: pycurl: libcurl link-time version is older than compile-time version.

To solve this, we need to do two more things to correct the system.

  1. modify file /etc/ld.so.conf.d/zend_server.conf to have below content,

    cat /etc/ld.so.conf.d/zend_server.conf
    /usr/lib64
    /usr/local/zend/lib


  2. run linux command ldconfig to build correct symbolic links.

Tuesday, February 22, 2011

PHP DB2 extension should support features like timeout checking.

I ran into very troublesome problem when I use DB2 connection from PHP to call RPG stored procedure. What happened is described in the following diagram.
  
As you can see, if calling a bad configured RPG stored procedure from PHP through DB2 extension on the same machine where Zend server and DB2 are installed, Zend Server may hang and it can not even be restarted from Zend Menu in green screen of i5/OS.

The appeared phenomenon is that QSQSRVR jobs is under MSGW status and seems the waiting status will never be broken. I am not sure which part exactly causes this. But, I think adding a time-out check mechanism in PHP DB2 extension on IBM i could be considered. The detailed discussion can be found from Zend Forums.

Monday, February 14, 2011

IBM Web Shpere MQ client for PHP on IBM i platform.

I am designing a log framework for my PHP code on IBM i. As the application will not only log some system level info but also many application level logs, I can expect that the log traffic will be crowed. In this case, I would like to let the app to throw log info into a message queue rather than to directly write into database.

However, I noticed that Zend Framework (v1.10) on IBM i only partially supports ActiveMQ as MQ client. I also find that there are at least two PHP extension in PECL to support IBM Web Sphere MQ: mqseries and SAM . However, as extensions, both of them are wrappers of under native code. So, they might have compiled libraries for Linux or MS Windows. But, there is no compiled package for IBM i platform.

So, we can see that we can not use IBM Web Sphere MQ with PHP on IBM i platform. In my case, I can not use Zend Server for IBM i and IBM Web Sphere together with Zend PHP. Therefore, using ActiveMQ on IBM i with Zend PHP on IBM will be only option (not consider other asynchronous message methods). But, I feel this is funny as I think IBM will not see ActiveMQ, which implements STOMP protocol, is used to replace Web Sphere MQ on IBM i and Zend will not see developer finally adband Zend server for IBM i and go back to linux, where more PHP vendors can compete at. As a developer, it is uncomfortable not to be able to use most nature way to finish project on IBM i.

If possible, we can put PHP engine on a Linux server and install MySQL server and DB2i storage engine on IBM i. then, PHP developer can walk around the DB2 Connect license issue and Web Sphere MQ client issue. However, if this happen, technically speaking, it will be easier for applicaton developer to shift whole application out of IBM i platform. Is this what IBM and Zend want? I guess they will not. So, I think Zend or IBM should release a PHP version Web Sphere MQ client for IBM i platform. I put my thoughts on Zend forum (link). I hope they will see it.

Tuesday, November 9, 2010

creating RESTful service with Zend_Rest_Route and Zend_Rest_Controller

After trying different ways to make RESTful WS in Zend Framework, I am aware that I can simply use Zend_Rest_Route and ZendRest_Controller to make "standard" RESTful WS in PHP. Especially, Zend_Rest_Route supports RESTful URI pattern like /parameterName/parameterValue/.... This is different from what I read from forums. I am using Zend Framework 1.10 in Zend Server 5.0.1 running on IBM i. Zend_Rest_Server is really not good choice to make RESTful service. Zend_Rest_Server needs to be further improved to meet the requirement of "standard" RESTful.

I tried Zend_Controller_Router_Route to implemented RESTful URI pattern. But, it is easier to use Zend_Rest_Route and Zend_Rest_Controller. Actually, Zend_Rest_Controller does nothing but defines several abstract methods, which map to relevant HTTP methods. But, our RESTful controller must extend from it. Below is the sample codes. In my environment, I can access it with this URL: http://localhost/jiaRESTfulWS/public/index/product/fish/number/100/

BootStrap class
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
 //adding this function in Bootstrap class to initilize Zend_Rest_Route.
 protected function _initRestRoute() {
  //getting an instance of zend front controller.
  $frontController = Zend_Controller_Front::getInstance ();
  //initializing a Zend_Rest_Route
  $restRoute = new Zend_Rest_Route ( $frontController );
  //let all actions to use Zend_Rest_Route.
  $frontController->getRouter ()->addRoute ( 'default', $restRoute );
 }
 
}

IndexController.php
class IndexController extends Zend_Rest_Controller
{
 
 public function init() {
  $this->getHelper ( 'viewRenderer' )->setNoRender ( true ); 
 }
 
 /**
  * The index action handles index/list requests; it should respond with a
  * list of the requested resources.
  */
 public function indexAction() {
  //HTTP code 500 might not good choice here.
  $this->getResponse ()->setHttpResponseCode ( 500 );
  $this->getResponse ()->appendBody ( "no list/index allowed" );
  
 } 
 
 /**
  * The get action handles GET requests and receives an 'id' parameter; it
  * should respond with the server resource state of the resource identified
  * by the 'id' value.
  */
 public function getAction() {  
  
  //I will return result in XML format.
  $this->getResponse ()->setHeader ( 'Content-Type', 'text/xml' );
  
  //Note: the Request object here is not HttpRequest. It is Zend controller request. This is the key!
  if ($this->getRequest ()->getParam ( "product" ) != NULL and $this->getRequest ()->getParam ( "number") != NULL ) {   
   //Initializing a dummy object for return. 
   $return = new Jia_Return ();
   $return->setProducts ( $this->getRequest ()->getParam ( "product" ) );
   $return->setQuantity ( $this->getRequest ()->getParam ( "number" ) );
   //We prevent the product has been found.
   //So, we set HTTP code 200 here.  
   $this->getResponse ()->setHttpResponseCode ( 200 );
  }    
   else {
    $return= new Jia_ErrorCode('no parameters!');
    //prevent the product is not found.
    $this->getResponse ()->setHttpResponseCode ( 200 );
   }
  
  print $this->_handleStruct( $return );
 
 }
 
 /**
  * The post action handles POST requests; it should accept and digest a
  * POSTed resource representation and persist the resource state.
  */
 public function postAction() {
  
 }
 
 /**
  * The put action handles PUT requests and receives an 'id' parameter; it
  * should update the server resource state of the resource identified by
  * the 'id' value.
  */
 public function putAction() {
 
 }
 
 /**
  * The delete action handles DELETE requests and receives an 'id'
  * parameter; it should update the server resource state of the resource
  * identified by the 'id' value.
  */
 public function deleteAction() {
 
 }
 
  
 /**
  * Handle an array or object result
  *
  * @param array|object $struct Result Value
  * @return string XML Response
  */
 protected function _handleStruct($struct) {

  $dom = new DOMDocument ( '1.0', 'UTF-8' );
  
  $root = $dom->createElement ( "Jia" );
  $method = $root;
  
  $root->setAttribute ( 'generator', 'Yiyu Blog' );
  $root->setAttribute ( 'version', '1.0' );
  $dom->appendChild ( $root );
  
  $this->_structValue ( $struct, $dom, $method );
  
  $struct = ( array ) $struct;
  if (! isset ( $struct ['status'] )) {
   $status = $dom->createElement ( 'status', 'success' );
   $method->appendChild ( $status );
  }
  return $dom->saveXML ();
 }
 
 /**
  * Recursively iterate through a struct
  *
  * Recursively iterates through an associative array or object's properties
  * to build XML response.
  *
  * @param mixed $struct
  * @param DOMDocument $dom
  * @param DOMElement $parent
  * @return void
  */
 protected function _structValue($struct, DOMDocument $dom, DOMElement $parent) {
  $struct = ( array ) $struct;
  
  foreach ( $struct as $key => $value ) {
   if ($value === false) {
    $value = 0;
   } elseif ($value === true) {
    $value = 1;
   }
   
   if (ctype_digit ( ( string ) $key )) {
    $key = 'key_' . $key;
   }
   
   if (is_array ( $value ) || is_object ( $value )) {
    $element = $dom->createElement ( $key );
    $this->_structValue ( $value, $dom, $element );
   } else {
    $element = $dom->createElement ( $key );
    $element->appendChild ( $dom->createTextNode ( $value ) );
   }
   
   $parent->appendChild ( $element );
  }
 }
 
}
Return.php
/**
 * A dummy class as return objec.
 * 
 * @author Yiyu Jia
 *
 */
class Jia_Return {
 
 /**
  * 
  * @var unknown_type
  */
 public $products;
 public $quantity;
 /**
  * @return the $products
  */
 public function getProducts() {
  return $this->products;
 }

 /**
  * @param $products the $products to set
  */
 public function setProducts($products) {
  $this->products = $products;
 }
 /**
  * @return the $quantity
  */
 public function getQuantity() {
  return $this->quantity;
 }

 /**
  * @param $quantity the $quantity to set
  */
 public function setQuantity($quantity) {
  $this->quantity = $quantity;
 }
 
}

ErrorCode.php
/**
 * An dummy error code class.
 * 
 * @author Yiyu Jia
 *
 */
class Jia_ErrorCode { 
 
 public $errorCode;
 
 function __construct($errMsg){
  $this->errorCode = $errMsg;
 }  

}

ZendStudio 7.2 project file can be downloaded from here.

Friday, November 5, 2010

A simple tutorial about creating Zend_Rest_Server based RESTful service.

It seems that RESTful WS is attracting more people to consider as RPC solution. Compared with SOAP based Web Service, RESTful has its advantage and disadvantage. RESTful WS is declared to be more scalability as it exactly maps HTTP methods  POST, GET, PUT, DELETE as a CRUD (Create, Request, Update, Delete) operations. So, if we design our RESTful WS as stateless, it could be more scalable in a cluster farm. It can get benefit from Cache mechanism of HTTP (limited to HTTP GET method configuration on proxy server in most time). However, it could be problem or ask for cost if we do not want the result to be cached. Furthermore, we can not always assume client Web browser has cache enabled. So, RESTful is not always right choice. Especially, it is not good choice when we develop an enterprise application which ask for complex data structure delivered between sub systems and it does not have extremely large volume of the concurrent accessing.

I will compose another post to describe my comparison about SOAP WS and RESTful WS and JSON-RPC. Here, I will show a simple demo about how to create Zend_Rest_Server based RESTful WS in Zend Studio. Zend_Rest_Server is not perfect. For instances, it can not work together with Zend_Action_Router_Route. It also asked for calling function by put "method=functionName" in requesting URL after the "?". This make some guys think it is not RESTful WS as some person said it is not good design. But, I think it is not wrong design at least.  Below is source for simple ZF based RESTful WS.
  1. Create a new ZF project in Zend Studio and name it as jiaRESTfulWS.
  2. Add autoloaderNamespaces[] = "Jia_" in application.ini to allow Zend Autoloader load Jia_* classes.
  3. Creating a action class DummyController under directory /application/controllers. 
  4. creating a function restAction() in DummyController .
  5. Creating a Jia_Hello class with sayHello($name) function under /library/Jia directory.
It is done. You need to pay attention on how to specify web service URI in the code if you use different project name and function names. Or, you might want to add alias in your apache httpd configuration file to simplify the URL. On my machine, this demo RESTful WS can be accessed with following URL: http://localhost/jiaRESTfulWS/public/index.php/Dummy/rest?method=sayHello&name=jia . See key source code as below,

Jia_Hello class
/**
 * This class contains function which will be used by Web service caller.
 * All business logics will be implented or called in these functions.
 * 
 * @author Yiyu Jia
 *
 */
class Jia_Hello {

 /**
  * 
  * @param string $name
  * @return string
  * 
  */
 public function sayHello($name){
  return "hello ".$name;
 }
}


DummyController class
/**
 * This class includes one function restAction(), wich has Zend_Rest_Server initialized.
 * However, you can only use URI with "?" like this "/rest?method=sayHello&name=jia". You 
 * can not have URI like "/rest/name/jia"
 * 
 * @author yiyu
 *
 */
class DummyController extends Zend_Controller_Action
{
 /**
  *  action named as rest.
  */
 public function restAction() {
  
  // disable layouts and renderers
  $this->getHelper ( 'viewRenderer' )->setNoRender ( true );
  
  // initialize REST server
  $server = new Zend_Rest_Server();
  // set REST service class
  $server->setClass ( 'Jia_Hello' ); 
    
  // handle request
  $server->handle ();
 
 }
 
}

Zend Studio 7.2 project file can be downloaded here. Also, I do not recommend to use Zend_Rest_Server for developing RESTful WS as I think it is old and uncompleted class. Zend_Rest_Route should be a better choice to make RESTful Web Service in PHP. Here is a simple tutorial about how to use Zend_Rest_Route and Zend_Rest_Controller to create RESTful Web Service. Creating RESTful service with Zend_Rest_Route and Zend_Rest_Controller

Saturday, October 30, 2010

A discussion about asynchronous programming in PHP and further

I read an article about asynchronous programming in PHP. It declares that lacking asynchronous programming is not limitation from PHP language. However, I think this is obviously the limitation of PHP.

Lacking of multi-thread features is the source of the limitation. PHP programmers have argued that they can use named pipe, node.js, libevent, Curl, Zend_Job, and other process control extensions to implement asynchronous functions in PHP. However, these methods are not core PHP feature. Therefore, there is no guarantee that these functions can be run on all platforms on which core PHP can run. For example, I wonder whether libevent can run on IBM i platform or not. Zend Server for IBM i supports Zend_Job. But it is not in Zend Server CE, which is free. Also, some extensions like PCNTL seems a solution based on multi process with shared memory. It is a inter-process implementation. Multithreading is a inner process implementation.

This limitation of PHP is because of the way of running PHP script too. PHP is known that it has less memory leak problem. This is not surprised as each PHP script is loaded into memory only when it need to be executed. After it is executed, it is flushed out of memory. Of course, PHP has no memory leak as it has no memory at all.This is because PHP inherits from perl as CGI programming language. Somebody will argue that PHP actually has optimizers and extensions like memcache. These make PHP looks like have some memory. However, optimizer is for caching operation code. memcache is for caching some data as a persistent storage. They can not make PHP to have real memory.

Since PHP has no memory, core PHP has no function like PipedInputStream, PipedOutputStream, and multi thread etc. As I presented in an old post, its static modifier means different life scope than other languages do. So, lacking of asynchronous programming feature is the limitation from PHP itself. It is confusing to discuss PHP lacks asynchronous feature and deny it is limitation from PHP language itself.

Also, in servlet world, people has been interested in changing "request per thread" architecture because of the challenge from multiplied Ajax calling from browser side. Leading by Jetty, both Jetty and Tomcat 7.0 has implemented asynchronous servlet API already. I will deeply investigate whether PHP is facing same challenge or not. Or, with Fastcgi, PHP does not need to worry about this at all.

Thursday, October 28, 2010

tutorial about setting up multiple breakpoints for different PHP script files in Zend Studio

After trying Zend Studio 7.2 and 8.0 Beta, I have to say that Zend Studio manual does not fully describe its features. Especially, I can not find info about how to properly set up multiple breakpoints in its manual .

What happened is, after initializing a ZF project with default settings in ZS, I find that I can only make debugging break point in the first PHP script, which is /public/index.php . Zend Debugger ignores other breakpoints set in other PHP scripts, where those complex logical are implemented. After studying, I find that we need to change the default debug configurations to make multiple breakpoints to work. The steps are as below,

1) right click your project in PHP Explorer window and select Properties for properties window.
2) Select  "PHP Include Path" --> "Libraries"
3) Remove the default libraries of Zend Framework, which belong to Zend Studio.
4) Add the Zend Framework directory under your local Zend server directory as library. Now you can see the screen like below,
5) Click menu "Run" --> "Debug Configurations..." . select or create your debug configuration settings.
6) Click "Configure..." button under the "server" tab for edit server window.
7) Click "path mapping" tab and create a path mapping entry, which has exactly same path for "server path" and "local path". You will see screen as below,
8) Click "Advanced" tab on "Debug Configurations" window and select radio button "Local copy if available. Otherwise, the server".

Now, you can see that Zend Debugger can stop at breakpoints in PHP scripts other than the first page scripts.

For better understand the debugger in Zend Studio, here is one link: click.

Thursday, October 14, 2010

Zend_Soap_Client and PHP http client do not share same native code

I was told by a senior PHP consultant that he can not successfully make Zend_Soap_Client call over the SSL. He runs his code on Zend Server running on i Series. Then, I told him that, if I were him, I will try to write a normal HTTP client to access the WSDL file over SSL first. The reason for me to approach in this way because,

  • SOAP is built on the top HTTP. So, SSL should not be business of SOAP. In other words, SOAP client shall rely on the HTTP client implement.
  • I THOUGHT that Zend_Soap_Client uses same native code as PHP http client.

However, I was wrong. He tested and found that he was able to do file_get_contents and retrieve https:// content from the server. Then, I started to trace the source code of Zend_Soap_Client. I found,
  1. Zend_Soap_Client is a wrapper around PHP SOAP extension.
  2. PHP SOAP is a thin layer. It quickly goes to native code at file called soap.php.
  3. Native c code of soap.php has its own logical to deal with proxy and SSL. Click Here to see C source code.
So, I was wrong. I can not regard that Zend_Soap_Client can support SSL just because PHP Http client can support SSL. They probably uses different version of native http client code. From this discussion, I get deeper understanding about architecture of PHP. I will probably write a article to compare Java and PHP.

BTW, PHP 5.3 version of Zend Server 5.0.2 on iSeries does not support Zend_Soap_Client to access web service over the SSL. However, Zend_Soap_Client work with SSL when the Zend Server was rolled back to version 5.0.1 . Zend_Soap_Client coming with Zend server 5.0.4 can be used to access Web service over one-way SSL. I have not tried mutual SSL with Zend_Soap_Client yet. But, it sounds not easy.

Also, to test Zend_Soap_Client access over one-way SSL can be as simple as below,

try {
 $soap_url = 'https://your.host/webservice?wsdl'; 
 
 $soap_client = new SoapClient ( $soap_url);
 
 var_dump ( $soap_client -> __getFunctions () );
 
} catch ( Exception $e ) {
 print_r ( $e );
 exit ();
}

Wednesday, October 6, 2010

Be sure to check httpd "AllowOverride" setting for your Zend Framework app

Yesterday, I installed Zend Server CE ver 5.0.3 Windows x86 on my machine. Then, I used Zend Studio 7.2 to create a default ZF project. However, I find that I always got 404 error that means page is not found.

How can it be? Zend Studio actually put whole project files under Apache httpd's htdocs folder already. First thing I suspect is that I dont have .htaccess  file defined or it defines wrong rules? Then, I spend time on finding .htaccess file and checking its rules definition. However, it seems there is nothing wrong but my ZF application can not run!

Finally, I go to Apache httpd configuration folder and open the httpd.conf file and zend.conf file. Here, I found the problem. And it is so trivial and I feel I am stupid that I wasted time on checking .htaccess files. Zend server sets its apache httpd configuration with "AllowOverride None". Therefore, those .htaccess file I keep on checking is totally ignored by httpd! I changed it to be "AllowOverride All" and my ZF application works immediately. This is not a safe configuration. However, it is just a local web server for developing purpose. It is Ok.

I do not know whether this could be called as Zend Server's bug or not. Zend Server or Zend Studio should modify this setting for developers if they declare themselves as seamless integrated development environment for ZF developers. However, it is really not difficult for developers to correct this setting if they keep in mind of this. After getting this lesson, I think I will always remember to check this setting after I freshly install a Zend Server. 

If interested, official site to describe Apache httpd "AllowOverride" configuration is here .