PHP

Setup MAMP (Mac, Apache, MySQL And PHP) on Mac OS X 10.5 Leopard

New Mac OS X 10.5 Leopard comes with new versions of Apache and PHP (Apache/2.2.6 (Unix) mod_ssl/2.2.6 OpenSSL/0.9.7l DAV/2 PHP/5.2.4), so it is quite easy to setup a MAMP server. Sure there are other ways to do the setup: You can build Apache, MySQL and PHP from sources, you can use MacPorts or you can use pre-build packages like MAMP or XAMPP. But in my opinion, because Apache and PHP are already installed, they are easy way to go and will minimize you work.

Apache

To enable pre-installed PHP, you have to edit httpd.conf file:

sudo vi /private/etc/apache2/httpd.conf

And uncomment next line:

LoadModule php5_module libexec/apache2/libphp5.so

If you want to make other configuration changes, for example define virtual hosts, it’s better to use user’s configuration file:

sudo vi /private/etc/apache2/users/[username].conf

After making changes, restart Apache aka Web Sharing. Go to System Preferences > Sharing and unselect and select again Web Sharing. That’s it. Now you have the Apache and PHP running. If there are any problems, you can examine the Apache error_log. Go to Console > /var/log > apache2 > error_log.

PHP

If you want to make changes to php.ini, do the following. Copy php.ini.default to php.ini:

sudo cp /private/etc/php.ini.default /private/etc/php.ini

And to make changes:

sudo chmod 644 /private/etc/php.ini
sudo vi /private/etc/php.ini
sudo chmod 444 /private/etc/php.ini

After making changes don’t forget to restart Apache.

MySQL

MySQL is a little trickier. It is not pre installed in OS X and in my opinion easiest way is to use binary from MySQL.com. So, download the current version, which is mysql-5.0.45-osx10.4-i686.pkg at the moment and install it. Then install MySQLStartupItem.pkg and copy MySQL.prefPane to OSX/Library/PreferencePanes. It seems to be that current versions preference pane is not quite compatible with OS X 10.5. It shows if the server is running or stopped, but you can’t star or stop with it. MySQL starts when the OS starts, but you can start or stop it manually from console:

sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
sudo /Library/StartupItems/MySQLCOM/MySQLCOM stop

MySQL with default settings use socket in /tmp and pre-installed PHP presumes it to be in /var/mysql, so you have to update the location in php.ini:

mysql.default_socket = /tmp/mysql.sock

Perhaps you could also use a symbolic link from /var/mysql/mysql.sock to tmp/mysql.soc. MySQL GUI Tools are also working nicely with new OS X 10.5.

Mac OS X 10.5

No you should have a MAMP server running nicely. If you want to make host name changes – for example you can use different names for localhost to take advantage Apache’s virtual hosting – edit hosts file:

sudo vi /private/etc/hosts

Minimal Web Services with XFire, Spring and PHP

If you have a Java web application implemented with Java 5 and Spring Framework, it is really easy to expose your POJOs as web services. In this example I use XFire and JSR 181 annotations for that. I’ll also make a small web service client example with PHP. The goal is to add web services to the existing Java code with absolute minimal code addition. I was about to add web service authentication with Acegi Security, but instead for now, there is no authentication in this example.

XFire has a quite versatile but scarce user’s guide. But it is a good start, so start with overview and quick start. Add XFire libraries and the depencies with the help of a Depency quide. This example works at least with the following libraries:

  • xfire-all-1.2.2
  • activation-1.1
  • commons-codec-1.3
  • commons-httpclient-3.0
  • commons.logging-1.0.4
  • mail-1.4
  • jaxen-1.1-beta-9
  • jdom-1.0
  • junit-3.8.1
  • servlet-api-2.3
  • spring-2.0
  • stax-api-1.0.1
  • wsdl4j-1.5.2
  • xbean-spring-2.5
  • wstx-3.0.1
  • XmlSchema-1.1
  • xfire-jsr181-api-1.0-M1
  • jaxb-xjc-2.0.1
  • jaxb-impl-2.0.1
  • jaxb-api-2.0
  • aopalliance-1.0
  • commons-beanutils-1.7.0

XFire 1.2.2 package comes with xbean-spring-2.6. There can be some problems with that version but at least version 2.5 is working with Spring 2.0.

First, add xfire-servlet.xml into WEB-INF directory. Here are the default settings from the user’s manual:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
  <import resource="classpath:org/codehaus/xfire/spring/xfire.xml"/>
    <bean id="jaxbTypeMappingRegistry"
        class="org.codehaus.xfire.jaxb2.JaxbTypeRegistry"
        init-method="createDefaultMappings" singleton="true"/>
    <bean id="webAnnotations"
        class="org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations"/>
    <bean id="handlerMapping"
        class="org.codehaus.xfire.spring.remoting.Jsr181HandlerMapping">
      <property name="typeMappingRegistry">
        <ref bean="jaxbTypeMappingRegistry"/>
      </property>
      <property name="xfire">
        <ref bean="xfire"/>
      </property>
      <property name="webAnnotations">
        <ref bean="webAnnotations"/>
      </property>
    </bean>
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
      <property name="urlMap">
        <map>
          <entry key="/">
            <ref bean="handlerMapping"/>
          </entry>
        </map>
      </property>
    </bean>
</beans>

Add xfire-servlet.xml into the Spring’s contextConfigLocation and XFireServlet in web.xml file:

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
    /WEB-INF/applicationContext.xml
    /WEB-INF/xfire-servlet.xml
  </param-value>
</context-param>
 
<servlet>
  <servlet-name>XFireServlet</servlet-name>
  <display-name>XFire Servlet</display-name>
  <servlet-class>org.codehaus.xfire.spring.XFireSpringServlet</servlet-class>
</servlet>
 
<servlet-mapping>
  <servlet-name>XFireServlet</servlet-name>
  <url-pattern>/servlet/XFireServlet/*</url-pattern>
</servlet-mapping>
 
<servlet-mapping>
  <servlet-name>XFireServlet</servlet-name>
  <url-pattern>/services/v1/*</url-pattern>
</servlet-mapping>

Let’s have a simply MinimizrFacade.java Java interface:

package com.minimizr.service;
 
import java.util.List;
import com.minimizr.service.domain.ExampleObject;
 
public interface MinimizrFacade {
  String getString();
  String echoString(String string);
  ExampleObject echoObject(ExampleObject exampleObject);
  List<exampleObject> loadExampleObjectList();
}

And let’s have another MinimizrService.java Java interface for web services:

package com.minimizr.service;
 
import java.util.List;
import javax.jws.WebService;
import com.minimizr.service.domain.ExampleObject;
 
@WebService
public interface MinimizrService {
  String getString();
  String echoString(String string);
  ExampleObject echoObject(ExampleObject exampleObject);
  List<exampleObject> loadExampleObjectList();
}

And for this example a ExampleObject.java Java object:

package com.minimizr.service;
 
public class ExampleObject {
  private String name;
  private Integer age;
 
  public Integer getAge() {
    return age;
  }
 
  public void setAge(Integer age) {
    this.age = age;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
}

And finally a MinimizrImpl.java Java implementation for the interfaces:

package com.minimizr.domain.logic;
 
import java.util.List;
import javax.jws.WebService;
import com.minimizr.service.ExampleObject;
import com.minimizr.service.MinimizrService;
 
@WebService(serviceName = "MinimizrService",
    endpointInterface = "com.minimizr.service.MinimizrService")
public class MinimizrImpl implements MinimizrFacade, MinimizrService {
  public String getString() {
    return "Example string";
  }
 
  public String echoString(String string) {
    return string;
  }
 
  public ExampleObject echoObject(ExampleObject exampleObject) {
    return exampleObject;
  }
 
  public List loadExampleObjectList() {
    /* Here you would get list of ExampleObjects for example from database
    and return it instead of null */
    return null;
  }
}

XFire does not support RPC-encoding but you can use XFire web services with PHP with document/literal style of SOAP.

Here is a really simple example to use all the exposed java web services in this example with NuSOAP PHP SOAP library. There are no checks for errors in the code:

<?php
require("../lib/nusoap.php");
$soapClient = new soapclient(
    "http://www.minimizr.com/ws/services/v1/MinimizrService?wsdl", "wsdl");
$proxyClass = $soapClient->getProxy();
 
// getString
$string = $proxyClass->getString();
print("<b>String:</b> " . $string["out"] . "<hr/>");
 
// echoString
$string = $proxyClass->echoString(array("in0" => "ABC"));
print("<b>String:</b> " . $string["out"] . "<hr/>");
 
// echoObject
$requestObject = array("name" => "John", "age" => 50);
$result = $proxyClass->echoObject(array("in0" => $requestObject));
$resultObject = $result["out"];
print("<b>Object:</b> name: " . $resultObject["name"]);
print(", age: " . $resultObject["age"] . "<hr/>");
 
// loadExampleObjectList
$exampleObjectList = $proxyClass->loadExampleObjectList();
foreach ($exampleObjectList["out"]["ExampleObject"] as $key => $value) {
  print($value["name"] . " " . $value["age"] . "<br/>");
}
?>

Authentication

Added November 14, 2006: Well, easiest and most straightforward way to secure web service is to use HTTP Authentication. It doesn’t need any additional code in the server side. While still looking for solution to use easily Acegi Security, I’ll add HTTP Authentication to this example. On the server side you’ll have to add security constraint into web.xml:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Protected Minimizr Web Services</web-resource-name>
    <url-pattern>/services/v1/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>minimizr.webservices.client</role-name>
  </auth-constraint>
</security-constraint>
 
<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Minimizr Realm</realm-name>
</login-config>
 
<security-role>
  <description>Required roles to use the Web Services</description>
  <role-name>minimizr.webservices.client</role-name>
</security-role>

And couple more lines into the PHP file. Credentials must be added into the wsdl url and proxy class. Notice that it is quite necessary to use SSL connection (https) with basic authentication since username and password are in clear text. You can use useHTTPPersistentConnection method to use persistent connection, if possible:

<?php
require("../lib/nusoap.php");
 
$username = "username";
$password = "password";
$method = "basic";
 
$soapClient = new soapclient(
  "https://$username:$password@www.minimizr.com/ws/services/v1/MinimizrService?wsdl",
  "wsdl");
$proxyClass = $soapClient->getProxy();
$proxyClass->setCredentials($username, $password, $method);
$proxyClass->useHTTPPersistentConnection();
...

Conclusion

It is no brainer to expose Java POJOs as web services with Spring, XFire and JSR-181 annotations. And it is as easy use those web services with Java or PHP or other platforms. I guess integrating Acegi Security with XFire web services needs a little bit more work. Any suggestions for the easiest way to implement it?

Additional recourses

Minimal How to Use Google Maps API With PHP

Google MapsThe goal of this how to is to easily add multiple markes into the map on your own site using Google Maps API and PHP.

Google Maps API key

  1. If you don’t already have, sign up for the Google Account.
  2. Sign up for the Google Maps API key. Read at least the higlights from the Google Maps API terms. Sign up for your site, forexample http://www.mysite.com/

After sign up you’ll get your key and an example html code. If you lost your key anytime, you can sign up again for the same site and use a new key. You can also sign up for multiple sites keys if needed. You’ll get different key for each site.

JavaScript

To add multiple markers on your map we’ll use some basic PHP code. Google’s example code is a good starting point for this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
  Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html;
    charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?
      file=api&amp;v=2&amp;key=ABCDEFGH..."
      type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[
    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(
        document.getElementById("map"));
        map.setCenter(
        new GLatLng(37.4419, -122.1419), 13);
      }
    }
    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map"
    style="width: 500px; height: 300px"></div>
  </body>
</html>

You have your API key on the html head and JavaScript to load on page load and div element to show the map. With map.setCenter(new GLatLng(37.4419, -122.1419), 13) you define the map’s center point and the zoom level. Here is an example.

To have some controls in the map, add this line into JavaScript load funtion:

map.addControl(new GSmallMapControl());

Add this JavaScript function to make markers:

function createMarker(point, text, title) {
  var marker = new GMarker(point,{title:title});
  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml(text);
  });
  return marker;
}

Add marker with this code:

var marker = createMarker(
new GLatLng(37.4419, -122.1419),
'Marker text', 'Example Title text');
map.addOverlay(marker);

Note that you can add in the markers any html code like links and images for example. So, the code looks now like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
  Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html;
    charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?
      file=api&amp;v=2&amp;key=ABCDEFGH..."
      type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[
    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(
        document.getElementById("map"));
        map.addControl(new GSmallMapControl());
        map.setCenter(
        new GLatLng(37.4419, -122.1419), 13);
        function createMarker(point, text, title) {
          var marker =
          new GMarker(point,{title:title});
          GEvent.addListener(
          marker, "click", function() {
            marker.openInfoWindowHtml(text);
          });
          return marker;
        }
        var marker = createMarker(
        new GLatLng(37.4419, -122.1419),
        'Marker text', 'Example Title text');
        map.addOverlay(marker);
      }
    }
    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map"
    style="width: 500px; height: 300px"></div>
  </body>
</html>

Here is an example.

PHP

In order to add multiple markes, we’ll use some PHP to iterate over some marker points. Let’s use an array in this example, but you could get the marker points for example from database or xml file. Put the following lines around marker adding lines:

<?php
$points = Array(1 => "37.4389, -122.1389",
2 => "37.4419, -122.1419",
3 => "37.4449, -122.1449");
foreach ($points as $key => $point) {
?>
var marker = createMarker(
new GLatLng(<?php echo $point ?>),
'Marker text <?php echo $key ?>',
'Example Title text <?php echo $key ?>');
map.addOverlay(marker);
<?php } ?>

And here is the final code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0
  Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html;
    charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?
      file=api&amp;v=2&amp;key=ABCDEFGH..."
      type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[
    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(
        document.getElementById("map"));
        map.addControl(new GSmallMapControl());
        map.setCenter(
        new GLatLng(37.4419, -122.1419), 13);
        function createMarker(point, text, title) {
          var marker =
          new GMarker(point,{title:title});
          GEvent.addListener(
          marker, "click", function() {
            marker.openInfoWindowHtml(text);
          });
          return marker;
        }
        <?php
        $points = Array(
        1 => "37.4389, -122.1389",
        2 => "37.4419, -122.1419",
        3 => "37.4449, -122.1449");
        foreach ($points as $key => $point) {
        ?>
        var marker = createMarker(
        new GLatLng(<?php echo $point ?>),
        'Marker text <?php echo $key ?>',
        'Example Title text <?php echo $key ?>');
        map.addOverlay(marker);
        <?php } ?>
      }
    }
    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map"
    style="width: 500px; height: 300px"></div>
  </body>
</html>

And here is the final example.

If you have let’s say hundereds or thousands and more markers in your map, you might want to give a try to Clusterer. It is an excellent and easy to use JavaScript library by Jef Poskanzer.

This how to showed only very basic usage of Google Maps API. To learn more Google Maps API has a good documentation and Mike has many excellent examples of the basics and more andvanced stuff.

Scroll to Top