Category Archives: MacPorts

Install PHP 7.0 in Mac OS X with MacPorts

I’ve used this process to install PHP 7.0 with MacPorts along side with PHP 5.6.

First make sure Mac OS X included Apache server is stopped:

$ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist

Install PHP7 and some of its modules (full list here):

$ sudo port install php70
$ sudo port install php70-apache2handler php70-cgi php70-gd php70-curl php70-intl php70-iconv php70-gettext php70-mbstring php70-imap php70-mcrypt php70-xmlrpc php70-mysql php70-openssl php70-sockets php70-zip php70-tidy php70-opcache php70-xsl php70-sqlite

Create the base php.ini file from the development example:

$ sudo cp /opt/local/etc/php70/php.ini-development /opt/local/etc/php70/php.ini

Find current timezone, add a backslash in between and put it in php.ini:

$ TIMEZONE=`sudo systemsetup -gettimezone | awk '{ print $3 }'`
$ TIMEZONE=$(printf "%s\n" "$TIMEZONE" | sed 's/[][\.*^$/]/\\&/g')
$ sudo sed -i.bak "s/;date.timezone =/date.timezone = \"${TIMEZONE}\"/g" /opt/local/etc/php70/php.ini

Update MySQL sockets if you are using it:

$ sudo sed -i.bak "s#pdo_mysql\.default_socket.*#pdo_mysql\.default_socket=`/opt/local/bin/mysql_config --socket`#" /opt/local/etc/php70/php.ini
$ sudo sed -i.bak "s#mysqli\.default_socket.*#mysqli\.default_socket=`/opt/local/bin/mysql_config --socket`#" /opt/local/etc/php70/php.ini

Now with this command you’ll see the installed PHP versions:

$ sudo port select --list php
Available versions for php:
	none
	php56 (active)
	php70

Select php70 as the active PHP version:

$ sudo port select php php70
Selecting 'php70' for 'php' succeeded. 'php70' is now active.

Enable PHP 7 in Apache:

$ cd /opt/local/apache2/modules
$ sudo /opt/local/apache2/bin/apxs -a -e -n php7 mod_php70.so

Restart Apache:

$ sudo /opt/local/etc/LaunchDaemons/org.macports.apache2/apache2.wrapper restart

You can check in the console the php version:

$ php -v
PHP 7.0.0 (cli) (built: Dec 12 2015 11:18:35) ( NTS )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies

If the current version is not 7.0 make sure that /opt/local/bin is defined before /usr/bin in the PATH variable:

$ echo $PATH
/opt/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

Also check that /opt/local/bin/php is pointing to /opt/local/bin/php70:

$ ls -l /opt/local/bin/php
lrwxr-xr-x  1 root  admin    20B Dec  5 23:25 /opt/local/bin/php -> /opt/local/bin/php70

If running phpinfo(); doesn’t show the 7.0 version check that only the module for 7.0 is loaded in /opt/local/apache2/conf/httpd.conf:

#LoadModule php5_module        modules/mod_php56.so
LoadModule php7_module        modules/mod_php70.so

php7

Fix “Communications link failure” in Java applications with MySQL

You may have problems connecting to MySQL from Java applications using Connector/J (the Java connector for MySQL) after upgrading/migrating MacPorts to a newer version. It happened to me after updating Mac OS X to El Capitan and upgrading MacPorts to work with it. Everything worked fine with phpMyAdmin and other applications using PHP but Java applications wouldn’t connect:

Exception in thread "main" java.lang.IllegalStateException: Cannot connect the database!
	at Main.main(Main.java:19)
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
	at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:983)
	at com.mysql.jdbc.MysqlIO.(MysqlIO.java:339)
	at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2252)
	at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2285)
	at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2084)
	at com.mysql.jdbc.ConnectionImpl.(ConnectionImpl.java:795)
	at com.mysql.jdbc.JDBC4Connection.(JDBC4Connection.java:44)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:404)
	at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:400)
	at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:327)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:247)
	at Main.main(Main.java:16)
Caused by: java.net.ConnectException: Connection refused
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
	at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:214)
	at com.mysql.jdbc.MysqlIO.(MysqlIO.java:298)
	... 15 more

You can test a simple connection in Java with this code in a file named Main.java:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Main {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/database_name";
        String username = "username";
        String password = "password";

        System.out.println("Connecting database...");

        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            System.out.println("Database connected!");
        } catch (SQLException e) {
            throw new IllegalStateException("Cannot connect the database!", e);
       }
    }
}

And running it like this (you’ll have to download the Java MySQL connector and place it in the same path with the .java file):

$ javac Main.java
$ java -cp .:./mysql-connector-java-5.1.37-bin.jar Main

I could connect to MySQL databases from the console using mysql so my server was running. I checked the usual configurations in my.cnf and didn’t see nothing wrong. The binding address was correct (it was 0.0.0.0 so connections from any IP could be done) and the socket file was also fine.

# Use default MacPorts settings
!include /opt/local/etc/mysql55/macports-default.cnf

[client]
port            = 3306
socket          = /opt/local/var/run/mysql55/mysqld.sock

[mysqld]
port            = 3306
socket          = /opt/local/var/run/mysql55/mysqld.sock
bind-address    = 0.0.0.0
max_allowed_packet = 256M

And then I saw it. Look at the include line. The problem was that the /opt/local/etc/mysql55/macports-default.cnf file in that include had been rewritten when MacPorts was updated and it had the skip-networking option enabled.

skip-networking

So the problem was solved by just commenting it out and restarting MySQL server.

Byobu: the text-based window manager and terminal multiplexer

Byobu is a text-based window manager and terminal multiplexer. This video is a great overview and tutorial on what it can do:

Install in Ubuntu:

$ sudo apt-get install byobu

Install in Mac OS X with brew:

$ brew install byobu

Install in Mac OS X with macports:

$ sudo port install python27 gettext libnewt coreutils gsed
$ curl -L -O https://launchpad.net/byobu/trunk/5.91/+download/byobu_5.91.orig.tar.gz
$ tar xzpf byobu_5.91.orig.tar.gz
$ cd byobu-5.91
$ ./configure
$ make
$ sudo make install

byobu

Ref: http://randomfoo.net/2014/01/14/byobu-on-mac-w-macports

Disable XDebug temporary while using BlackfireIO

BlackfireIO and XDebug are not the best friends because the last one can affect the precission of the profile results. So it’s recommended to disable XDebug while using BlackfireIO to get the best results.

blackfire

I just rename the XDebug’s config file and restart Apache to do so:

$ sudo mv /opt/local/var/db/php56/xdebug.ini /opt/local/var/db/php56/xdebug.ini.bak
$ sudo /opt/local/etc/LaunchDaemons/org.macports.apache2/apache2.wrapper restart

And when I’m finished with BlackfireIO I put it back:

$ sudo mv /opt/local/var/db/php56/xdebug.ini.bak /opt/local/var/db/php56/xdebug.ini
$ sudo /opt/local/etc/LaunchDaemons/org.macports.apache2/apache2.wrapper restart

Manual install and configuration of blackfire.io for Mac Ports in Mac OS X

blackfire.io is an awesome profiler for PHP done by SensioLabs, the company behind Symfony2. It automatically instruments your code to gather data about consumed server resources like memory, CPU time, and I/O. It’s very useful to find bottlenecks in your code.

blackfire.io is made of five main components:

  • The Agent is a server-side daemon that aggregates and forwards profiles to blackfire.io
  • The Probe is a PHP extension that gathers the raw performance profiles
  • The Client is a CLI tool used to trigger profiling
  • The Companion is a web browser extension used to trigger profiling
  • The Website is used to visualize the profiles

blackfire

To use it in Mac OS X with Mac Ports you have to do a manual installation. Here is the different components installation process.

Agent

Download and install it’s files:

$ curl -O http://packages.blackfire.io/binaries/blackfire-agent/1.5.1/blackfire-agent-darwin_amd64.tar.gz
$ tar xzvf blackfire-agent-darwin_amd64.tar.gz
$ sudo mv etc/blackfire /opt/local/etc/
$ sudo chown -R root:admin /opt/local/etc/blackfire
$ sudo mv usr/share/man/man1/blackfire-agent.1.gz /opt/local/share/man/man1/
$ sudo chown root:admin /opt/local/share/man/man1/blackfire-agent.1.gz
$ sudo mv usr/bin/blackfire* /opt/local/bin/
$ sudo chown root:admin /opt/local/bin/blackfire*
$ sudo mkdir -p /opt/local/var/log/blackfire
$ sudo ln -s /opt/local/etc/blackfire /usr/local/etc/blackfire

Create an agent configuration file in /opt/local/etc/blackfire/agent changing the log/socket files to the paths inside Mac Ports installation (/opt/local) and with your server id and token from https://blackfire.io/account/credentials#server:

[blackfire]
ca-cert=
collector=https://blackfire.io
log-file=/opt/local/var/log/blackfire/agent.log
log-level=1
server-id=d8108598-7a7a-4c5e-8f03-d0bccadc0931
server-token=91bde3fa9350479ba84f90acab46b680142c0f6fe8154a649e82d0d2ddadfa93
socket=unix:///opt/local/var/run/blackfire-agent.sock
spec=

Now you can run it with this command:

$ sudo blackfire-agent

But it’s better to register a service using launchctl. Create a file called /opt/local/etc/LaunchDaemons/com.sensiolabs.blackfire-agent/com.sensiolabs.blackfire-agent.plist with this content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Disabled</key>
        <false/>
        <key>KeepAlive</key>
        <true/>
        <key>Label</key>
        <string>com.sensiolabs.blackfire-agent</string>
        <key>ProgramArguments</key>
        <array>
            <string>/opt/local/bin/blackfire-agent</string>
        </array>
        <key>RunAtLoad</key>
        <false/>
    </dict>
</plist>

Make sure this file is owned by root and create an executable link to it in /Library/LaunchDaemons/com.sensiolabs.blackfire-agent.plist:

$ sudo chown root:admin /opt/local/etc/LaunchDaemons/com.sensiolabs.blackfire-agent/com.sensiolabs.blackfire-agent.plist
$ sudo ln -s /opt/local/etc/LaunchDaemons/com.sensiolabs.blackfire-agent/com.sensiolabs.blackfire-agent.plist /Library/LaunchDaemons/com.sensiolabs.blackfire-agent.plist
$ sudo chmod 755 /Library/LaunchDaemons/com.sensiolabs.blackfire-agent.plist

Load the service configuration file:

$ sudo launchctl load /Library/LaunchDaemons/com.sensiolabs.blackfire-agent.plist

And from now on you’ll be able to start and stop it as any other service:

$ sudo launchctl start com.sensiolabs.blackfire-agent
$ sudo launchctl stop com.sensiolabs.blackfire-agent

You can check if it’s really running using :

$ sudo ps x | grep blackfire
  751   ??  Ss     0:00.09 /opt/local/bin/blackfire-agent

Probe

This is the extension used in the HTTP server. You need a different binary file depending on your PHP version. This script will download and configure it for you, you only need to change the server id and token:

$ PHP_VER=`php -v | head -n 1 | awk -F ' ' '{print $2}' | tr -d . | cut -c1-2`
$ EXT_DIR=`php -i | grep 'extension_dir' | awk -F ' => ' '{print $2}'`
$ sudo curl -o ${EXT_DIR}/blackfire.so http://packages.blackfire.io/binaries/blackfire-php/1.9.2/blackfire-php-darwin_amd64-php-${PHP_VER}.so
$ sudo chmod 755 ${EXT_DIR}/blackfire.so
$ PHP_INI=`php --ini | grep "Loaded Configuration File" | awk -F ' ' '{print $4}'`
$ echo "

[blackfire]
extension=\"${EXT_DIR}/blackfire.so\"
blackfire.agent_timeout=0.25
blackfire.agent_socket=unix:///opt/local/var/run/blackfire-agent.sock
blackfire.log_file=/opt/local/var/log/blackfire/agent.log
blackfire.server_id=d8108598-7a7a-4c5e-8f03-d0bccadc0931
blackfire.server_token=91bde3fa9350479ba84f90acab46b680142c0f6fe8154a649e82d0d2ddadfa93" | sudo tee -a $PHP_INI

Restart your HTTP server (Apache in my case) and also test with this command if the extension is correctly loaded by PHP:

$ php -m | grep blackfire
blackfire

Client

The client binary file is installed with the Agent in /opt/local/bin/blackfire but you can also download and install it separately:

$ curl http://packages.blackfire.io/binaries/blackfire-agent/1.5.1/blackfire-cli-darwin_amd64 > blackfire
$ sudo chown root:admin blackfire
$ sudo mv blackfire /opt/local/bin/blackfire

Now configure the client file with the credentials from https://blackfire.io/account/credentials#client:

$ blackfire config

This will create a file in your home folder called ~/.blackfire.ini. You’ll have to update its socket value so it’s the same as the one used in the Agent configuration file:

[blackfire]
agent-socket=unix:///opt/local/var/run/blackfire-agent.sock
ca-cert=
client-id=543425c4-cb4f-3aff-c543-34d5aeeff4fd
client-token=ec843b4356997915cabb0a1b7be129e73d7c22a587103e523ea8b9a1e541b2d4
endpoint=https://blackfire.io
timeout=15s

Companion

The companion is only available for Google Chrome at the moment from here: https://chrome.google.com/webstore/detail/blackfire-companion/miefikpgahefdbcgoiicnmpbeeomffld. Install it and you’ll see a new icon in your browser that displays the different profiler slots.

Once everything is installed, configured and running just go to the URL in your server you want to profile and click “Profile!” in the Companion.

blackfire-companion

Ref: https://blackfire.io/getting-started