SOAP HTTP/1.1 500 Internal Service Error

August 5th, 2010 No comments

When you get a HTTP/1.1 500 Internal Service Error http header while using the PHP  SoapServer->handle() method as response, while all other output seems fine: Check if the request handler $soapserver->handle() is called only once. Multiple method calls on this method can produce this error if the first handling generates a service error, and the second call does not.

If you need the SOAP headers for processing or passing to the operation object before handling the request, use $request = file_get_contents(“php://input”) instead of $request = $soapserver->getLastRequest(). It seems $soapserver->getLastRequest() can’t be called before you call $soapserver->handle().

This will also make your webservice considerably faster for all operations for which SoapServer::handle() is called twice.

Categories: PHP Tags:

Invert a GPS GPX format track file

July 12th, 2010 No comments

I ran into the issue of inverting a track in garmin’s roadtrip application for osx. It Can’t. It can invert routes, but not tracks. I created a little online tool to invert tracks. Just export a track by using the folder export tool (only one track should be in the folder). You can find it at the GPX gps tools – GPX track inverter page.

Categories: Electronics, Gadgets Tags:

Polar CS200 review

February 14th, 2010 No comments

I recently bought a Cube Sting HPC X0 mountain bike outfitted with a Polar CS200 bike computer. I also bought every available sensor for the computer. So it is capable of showing heart rate, cadence and speed.

Feature wise this bike computer is excellent. It has a patented feature called ownzone, which is pretty cool. This feature guides you through your warm up and determines what the best range of heart rates is to train in. This can change from training to training because of psychological or physical changes in your body. Like not being fully recovered from a previous training, or when you are in the process of catching a cold, or when you’re stressed out.

Every training session is recored when you press start. The recorded data can be transferred to a website owned by polar. You can view your training history on calendars, in graphs and in tables on that website.
Transferring files to the polar website www.polarpersonaltrainer.com to record a personal dairy requires a microphone and a windows computer. There currently is no plugin for OSX to transfer exercise files from the CS200 to polarpersonaltrainer.com. A bit of a disappointment.

My first impressions where pretty bad. I had a few problems with speed dropping out whenever I went above about 30km/h. I moved the speed sensor up the fork to decrease the distance between the computer unit and the speed sensor. This helped, but while in the recommended heart rate range. If the beep signal is enabled and it begins to beep when I’m over the recommended heart range zone while I’m above 30km/h it will still fail to record the speed properly while it is beeping. The solution is to disable the beep and watch your heart rate from time to time. Not the ideal solution, it should work fine with the beep enabled. I can still move the sensor up about 2-3cm, but it’ll be at the rim of my wheel. So I’ll try that and see if that helps.

Overall, I think it’s very useful to exercise with a heart rate monitor. I don’t have a “start too fast” problem any longer. I can maintain a certain heart rate and just keep going for a few hours. The Polar CS200 is a pretty good unit, as long as it works like it should. So a tip while mounting, mount it as high up the fork as you can.

A simple error handler for PHP

December 25th, 2009 No comments

What is the best way to handle your PHP application errors? There is no single good answer to that question. It all depends on how your application works, what environment the application runs in and also how maintenance is performed.

But one thing is the same for every application. You might already know that showing errors in your application to clients is not a very good practice. It’s a security risk because users can learn about the internals of your server and your application. Besides that, PHP error messages do not mean anything to a user of your application so it is pointless to show them what is wrong internally.
Alternatively you should use try and catch constructs to show friendly error messages to the users on the client side of your application if errors should be displayed to the user when they occur.

1
2
3
try {
} catch() {
}

You can use trigger_error() with the predefined error types E_USER_* to trigger your own application errors. For example to trigger PHP errors when your application encounters a MySQL error:

1
2
$query = 'SELECT YEAR(NOW())';
$result = mysql_query($query) or trigger_error(mysql_error().' - '.$query, E_USER_ERROR));

This way MySQL errors will be visible for you, but you do not give away anything about your database model to clients.
To see which predefined error constants there are available, see: http://www.php.net/manual/en/errorfunc.constants.php. A useful thing to note is that triggering notes or warnings does not stop the script from executing further. If you need to break the script and stop it from continuing, trigger an error.

So what can you do to get notified of PHP errors yourself, without having to keep up with the apache error log while not displaying any errors in the browser on the client side on your production application?
I’ve created a simple error handler that can replace or accompany the default PHP error handler.
This is a useful way of getting notified of errors, because you will get the errors in your mailbox directly when the error occurs. So you will know an error has occurred before a user can even send a bug report. This is not a solution for all situations, but it can sure be useful in some cases to get notified of errors you would otherwise miss, or would not be reported by users. Another useful feature is that you will receive the state of variables at the moment the error occurs. This can be immensely useful for debugging.

Here is the full error handler file (error_handler.php). You can put it into a PHP include directory so you can include it anywhere, or you can put it in one of the directories of your application.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
<?php
/*
 * Just a simple error handler.
 * It sends mails now, but can easily be modified to store the errors in a database instead of sending mails.
 * 
 * It optionally requires a database table for error checksums, this way you only get each error only once in your mailbox.
 * 
 * It's not very prety yet, but it is functional.
 * 
 * @author Oxidiser
 * @version 2.0
 * 
CREATE TABLE `error_checksums` (
  `checksum` varchar(32) collate utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`checksum`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
 */
// Mail where error e-mails should end up.
define('ERROR_REPORT_EMAIL', "someemailaddress@somedomain.com");
// Define if the original PHP error handler should also handle the error.
define('PHP_ERROR_HANDLER_ACTIVE', false);
// Should the error handler use checksums to prevent sending dulicate error messages?
define('USE_DATABASE', false);
// MySQL db options
define('MYSQL_HOST', "localhost");
define('MYSQL_USER', "");
define('MYSQL_PASSWORD', "");
define('MYSQL_DATABASE', "");
// Never display any errors to clients.
ini_set('display_errors', 0);
 
// Handle every error type. Good for test enviroment.
error_reporting(E_ALL);
// Handle every error type except notices and strict warnings. Good for the production enviroment.
//error_reporting(E_ALL & ~ E_NOTICE | E_STRICT);
 
// If error handler is not yet registered.
if(!is_callable('lookup_ErrorHandler')) {
    /**
     * Fetches an instance of the ErrorHandler object and calls the handleError() method;
     *
     * @param integer $errNo Contains the level of the error raised, as an integer.
     * @param string $errMsg Contains the error message, as a string.
     * @param string $fileName Contains the filename that the error was raised in, as a string.
     * @param integer $lineNum Contains the line number the error was raised at, as an integer.
     * @param array $vars An array that points to the active symbol table at the point the error occurred. In other words, errcontext will contain an array of every variable that existed in the scope the error was triggered in. User error handler must not modify error context.
     * @return void
     * 
     */
    function lookup_ErrorHandler ($errNo, $errMsg, $fileName, $lineNum, $vars)
    {
        // Run trough all error types.
        // To disable one of the error types, just comment out that case.
        // It might be useful to disable the notice error levels for sloppy programmers for instance.
        switch($errNo) {
            case E_ERROR:
            case E_WARNING:
            case E_PARSE:
            case E_USER_ERROR:
            case E_USER_WARNING:
            case E_STRICT:
            case E_COMPILE_ERROR:
            case E_COMPILE_WARNING:
            case E_CORE_ERROR:
            case E_CORE_WARNING:
            case E_RECOVERABLE_ERROR:
            case E_NOTICE:
            case E_USER_NOTICE:
                ErrorHandler::getInstance(ERROR_HANDLER_SUBJ_APPEND)->handleError($errNo, $errMsg, $fileName, $lineNum, $vars);
                break;
            default:
                // Error type should not be handled. Do nothing.
                break;
        }
        // Do or don't execute PHP internal error handler, return false if it should execute the PHP error handler, true if it should not.
        return !PHP_ERROR_HANDLER_ACTIVE;
    }
}
/**
 * This class replaces the default PHP error handler.
 * 
 * @param string $subjAppend This should contain the prefix for the e-mail subject. Useful for sorting e-mails by website when using the same error handler, when you for instance, place the error handler in an include directory. 
 * @version 1.0
 * @author Oxidiser
 * 
 */
class ErrorHandler
{
    /*
     * @var mixed (array with strings containing every error encountered during script execution)
     */
    public $errorsARR;
    /*
     * @var string A variable trace.
     */
    public $vars;
    /*
     * @var string (containing a string to prepend the error subject e-mail)
     */
    public $subjectAppend;
    /*
     * @var ErrorHandler
     */
    private static $instance;
    /*
     * @var MySQL link identifier
     */
    protected $_errorDb;
    /**
     * Create a new instance of the ErrorHandler object.
     * 
     * @param string $subjAppend The string that should be appended to the subject.
     * @return void
     */
    private function __construct($subjAppend)
    {
        $this->errormail = ERROR_REPORT_EMAIL;
        $this->subjectAppend = $subjAppend;
        $this->errortype = array(E_ERROR => 'Error',
                                 E_WARNING => 'Warning',
                                 E_PARSE => 'Parsing Error',
                                 E_NOTICE => 'Notice',
                                 E_CORE_ERROR => 'Core Error',
                                 E_CORE_WARNING => 'Core Warning',
                                 E_COMPILE_ERROR => 'Compile Error',
                                 E_COMPILE_WARNING => 'Compile Warning',
                                 E_USER_ERROR => 'User Error',
                                 E_USER_WARNING => 'User Warning',
                                 E_USER_NOTICE => 'User Notice',
                                 E_STRICT => 'Runtime Notice',
                                 E_RECOVERABLE_ERROR => 'Catchable Fatal Error'
                                );
        $this->errorsARR = array();
        if(USE_DATABASE) {
            // Database should be used, connect to MySQL instance.
            $this->_errorDb = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD);
            // Select the apropriate database.
            mysql_select_db(MYSQL_DATABASE, $this->_errorDb);
        }
    }
    /**
     * Clone the object (required for the singleton)
     * 
     * @return void
     */
    private function __clone ()
    {}
    /**
     * Returns the instance of the ErrorHandler object.
     *
     * @param string $subjAppend This should contain the prefix for the e-mail subject. Usefull for sorting e-mails by website.
     * @return ErrorHandler
     */
    public static function getInstance ($subjAppend)
    {
        if(!ErrorHandler::$instance instanceof self) {
            ErrorHandler::$instance = new self($subjAppend);
        }
        return ErrorHandler::$instance;
    }
    /**
     * This mehtod actually handles the errors recieved from the PHP core.
     *
     * @param integer $errNo Contains the level of the error raised, as an integer.
     * @param string $errMsg Contains the error message, as a string.
     * @param string $fileName Contains the filename that the error was raised in, as a string.
     * @param integer $lineNum Contains the line number the error was raised at, as an integer.
     * @param array $vars An array that points to the active symbol table at the point the error occurred. In other words, errcontext will contain an array of every variable that existed in the scope the error was triggered in. User error handler must not modify error context.
     * @return void
     * 
     */
    public function handleError($errNo, $errMsg, $fileName, $lineNum, $vars)
    {
        if(USE_DATABASE) {
            // Use database for checksums.
            // Check checksum in the hope of reducing server load by only mailing errors once.
            $errorChecksum = md5($errNo . $errMsg . $fileName . $lineNum);
            // Check if checksum exists in database.
            // @todo What is faster? Check with a select statement like it does now, or only do an insert query and check for an exception (mysql error, primairy key already exists)?
            $q = mysql_query("SELECT checksum FROM error_checksums WHERE checksum = '{$errorChecksum}'", $this->_errorDb) or trigger_error('Something went wrong with the error handler checksum check query: '.mysql_error(), E_USER_ERROR);
            if(mysql_num_rows($q) > 0) {
                // Error already mailed. Return without adding error to array in object and adding checksum to the database.
                return 0;
            }
            // Add checksum to database.
            mysql_query("INSERT INTO error_checksums (checksum) VALUES ('{$errorChecksum}')", $this->_errorDb) or trigger_error('Something went wrong with the error handler checksum insert query: '.mysql_error(), E_USER_ERROR);
        }
        // Get vars from thrown error.
        $this->vars = $vars;
        // Get the current date.
        $dt = date("Y-m-d H:i:s (T)");
        // Get the next empty key (auto increment).
        $nextKey = count($this->errorsARR);
        // get defined vars.
        $this->errorsARR[$nextKey]['date'] = $dt;
        $this->errorsARR[$nextKey]['errno'] = $errNo;
        $this->errorsARR[$nextKey]['errtype'] = $this->errortype[$errNo];
        $this->errorsARR[$nextKey]['errmessage'] = $errMsg;
        $this->errorsARR[$nextKey]['script'] = $fileName;
        $this->errorsARR[$nextKey]['url'] = 'http://'.$_SERVER['SERVER_NAME'].($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : ($_REQUEST['SCRIPT_NAME'] ? $_REQUEST['SCRIPT_NAME'] : ($_ENV['SCRIPT_NAME'] ? $_ENV['SCRIPT_NAME'] : ($PHP_SELF ? $PHP_SELF : 'oopsnoscript')))) . ($_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '');
        $this->errorsARR[$nextKey]['lineno'] = $lineNum;
        // Get the state of the superglobals at the point of the error.
        $this->errorsARR[$nextKey]['session'] = $_SESSION;
        $this->errorsARR[$nextKey]['request'] = $_REQUEST;
        if(USE_DATABASE) {
            $this->errorsARR[$nextKey]['checksum'] = $errorChecksum;
        }
        if(isset($_SERVER['REMOTE_ADDR'])) {
            // Remote address is set, so store the client IP.
            $this->errorsARR[$nextKey]['user'] = $_SERVER['REMOTE_ADDR'];
        } else {
            // Unknown remote address.
            $this->errorsARR[$nextKey]['user'] = "Unknown";
        }
        // Extract the filename.
        $tmpArr = explode('/', $fileName);
        $errorFileName = array_pop($tmpArr);
        // Set the subject for this errors e-mail.
        $this->errorsARR[$nextKey]['subject'] = $this->errortype[$errNo] . ' in ' . $errorFileName. ' line #' . $lineNum;
    }
    /**
     * Destructor for the object. Sends (unique if checksums are used) errors once for each script execution at the end of execution.
     *
     * @return void
     */
    function __destruct ()
    {
        // Check if any errors were triggered during execution.
        if (count($this->errorsARR) > 0) {
            // Set headers for error mails.
            $headers = "From: \"somesite.nl Error reporter\" <errorhandler@somesite.nl>\n";
            $headers .= "Return-Path: <errorhandler@somesite.nl>\n";
            $headers .= "MIME-Version: 1.0\n";
            $headers .= "Content-Type: text/HTML; charset=ISO-8859-1\n";
            // Go through each error that was encountered.
            foreach($this->errorsARR as $err) {
                // Create content for error mail. 
                $content = "<table width=\"100%\" style=\"border:1px solid;\">";
                $content .= "<tr><td style=\"border:1px solid; background-color:#9FC2FF;\" colspan=\"2\"><strong>Message & Vitals</strong></td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>Error #</strong></td><td style=\"border:1px solid;\">{$err['errno']}</td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>Error type</strong></td><td style=\"border:1px solid;\">{$err['errtype']}</td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>Error message</strong></td><td style=\"border:1px solid;\">{$err['errmessage']}</td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>Date & time</strong></td><td style=\"border:1px solid;\">{$err['date']}</td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>URL</strong></td><td style=\"border:1px solid;\">{$err['url']}</td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>File</strong></td><td style=\"border:1px solid;\">{$err['script']}</td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\"><strong>Line</strong></td><td style=\"border:1px solid;\">{$err['lineno']}</td></tr>";
                if(USE_DATABASE) {
                    $content .= "<tr><td style=\"border:1px solid;\"><strong>Error checksum</strong></td><td style=\"border:1px solid;\">{$err['checksum']}</td></tr>";
                }
                $content .= "<tr><td style=\"border:1px solid; background-color:#9FC2FF;\" colspan=\"2\"><strong>\$_SERVER</strong></td></tr>";
                // Format the server superglobal.
                foreach($_SERVER as $key=>$val) {
                    $content .= "<tr><td style=\"border:1px solid;\"><strong>{$key}</strong></td><td style=\"border:1px solid;\">{$val}</td></tr>";
                }
                $content .= "<tr><td style=\"border:1px solid; background-color:#9FC2FF;\" colspan=\"2\"><strong>\$_REQUEST</strong></td></tr>";;
                // Format the request superglobal.
                foreach($err['request'] as $key=>$val) {
                    $content .= "<tr><td style=\"border:1px solid;\"><strong>".print_r($key, true)."</strong></td><td style=\"border:1px solid;\"><pre>".print_r($val, true)."</pre></td></tr>";
                }
                $content .= "<tr><td style=\"border:1px solid; background-color:#9FC2FF;\" colspan=\"2\"><strong>\$_SESSION</strong></td></tr>";;
                // Format the session superglobal.
                foreach($err['session'] as $key=>$val) {
                    $content .= "<tr><td style=\"border:1px solid;\"><strong>".print_r($key, true)."</strong></td><td style=\"border:1px solid;\"><pre>".print_r($val, true)."</pre></td></tr>";
                }
                $content .= "<tr><td style=\"border:1px solid; background-color:#9FC2FF;\" colspan=\"2\"><strong>Stack trace</strong></td></tr>";
                $content .= "<tr><td style=\"border:1px solid;\" colspan=\"2\"><pre>".print_r($this->vars, true)."</pre></td></tr>";
                $content .= "</table>";
                // Dispatch the error mail.
                mail($this->errormail, $this->subjectAppend.' '.$err["subject"], $content, $headers);
            }
        }
        // Restore the deafult PHP error handler.
        restore_error_handler();
        // Restore the default PHP config value.
        ini_restore('display_errors');
    }
}
// Set the custom error handler to handle the errors.
set_error_handler('lookup_ErrorHandler');

Here is a small file with which you can test the error handler:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
define("ERROR_HANDLER_SUBJ_APPEND", 'WEBSITE IDENTIFIER');
// You can use this error handler by simply including it in your code. Preferably as high in the execution chain as possible.
// Include error handler from include path dir.
//include_once("error_handler.php");
// Include with absolute path.
include_once(dirname(__FILE__)."/error_handler.php");
 
session_start();
$_SESSION['justatest'] = array('anarraykey' => 'withanarrayvalue');
 
trigger_error('This is just a test.', E_USER_WARNING);
Categories: PHP Tags: , , ,

Using a custom view helper in Zend Framework to create breadcrumbs

December 15th, 2009 1 comment

I don’t think I am the only one who needs to put breadcrumbs on a page with zend framework. So I’ll share my helper with you. You can use this helper in you views to set the breadcrumbs.

You can use this helper like you use the HeadTitle helper, it is based on that.
So, in you layout, select which separator you want to use, and if you want to use automatic escaping or not (Can’t use this if you use urls). You can also set a prefix, postfix and indent if you want, just like with the HeadTitle helper. You can set, append and prepend items to the breadcrumb trail.

This is the code for the layout and also an example of prepending an item to the breadcrumb:

1
2
3
4
5
6
7
8
9
10
  <?php
    // Set the separator for the breadcrumbs.
    $this->breadCrumb()->setSeparator(' > ');
    // Disable the auto escaping of html.
    $this->breadCrumb()->setAutoEscape(false);
    // Set the first (default) element of the breadcrumbs.
    $this->breadCrumb("Home", "/", Zend_View_Helper_Placeholder_Container_Abstract::PREPEND);
    // Display the breadcrumb.
    echo $this->breadCrumb();
    // ...

This is an example of the code for a view script:

1
2
3
4
5
<?php
// Set breadcrumbs for this view.
$this->breadCrumb($this->placeholder('category_name'), $this->url(array('category' => $this->placeholder('category_url_name')), 'category_route', true));
$this->breadCrumb($this->placeholder('subject_name'));
// ...

The full helper:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
<?php
/** Zend_View_Helper_Placeholder_Container_Standalone */
require_once 'Zend/View/Helper/Placeholder/Container/Standalone.php';
 
/**
 * Helper for setting and retrieving breadcrumbs for HTML.
 * Based on the HeadTitle helper.
 *
 * @version 1.0
 * @uses Zend_View_Helper_Placeholder_Container_Standalone
 */
class Zend_View_Helper_BreadCrumb extends Zend_View_Helper_Placeholder_Container_Standalone
{
    /**
     * Registry key for placeholder
     * @var string
     */
    protected $_regKey = 'Zend_View_Helper_BreadCrumb';
 
    /**
     * Whether or not auto-translation is enabled
     * @var boolean
     */
    protected $_translate = false;
 
    /**
     * Translation object
     *
     * @var Zend_Translate_Adapter
     */
    protected $_translator;
 
    /**
     * Container for the urls of the items.
     * 
     * @var Zend_View_Helper_Placeholder_Container
     */
    protected $_urls;
 
    /**
     * Retrieve placeholder for title element and optionally set a new item.
     *
     * @param  string $title
     * @param  string $url
     * @param  string $setType
     * @param  string $separator
     * @return Zend_View_Helper_BreadCrumb
     */
    public function breadCrumb($title = null, $url = null, $setType = Zend_View_Helper_Placeholder_Container_Abstract::APPEND)
    {
        // Initialize the url placeholder container if it is not created yet.
        if(!is_object($this->_urls)) $this->_urls = new Zend_View_Helper_Placeholder_Container();
        if ($title) {
            // Title must be given.
            if ($setType == Zend_View_Helper_Placeholder_Container_Abstract::SET) {
                // Reset the objects and set the first item.
                $this->set($title);
                $this->_urls->set($url);
            } elseif ($setType == Zend_View_Helper_Placeholder_Container_Abstract::PREPEND) {
                // Prepend an item to the breadcrumb.
                $this->prepend($title);
                $this->_urls->prepend($url);
            } else {
                // Append an item to the breadcrumb.
                $this->append($title);
                $this->_urls->append($url);
            }
        }
        // Return self for chaining and display of the breadcrumbs.
        return $this;
    }
 
    /**
     * Sets a translation Adapter for translation
     *
     * @param  Zend_Translate|Zend_Translate_Adapter $translate
     * @return Zend_View_Helper_BreadCrumb
     */
    public function setTranslator($translate)
    {
        if ($translate instanceof Zend_Translate_Adapter) {
            $this->_translator = $translate;
        } elseif ($translate instanceof Zend_Translate) {
            $this->_translator = $translate->getAdapter();
        } else {
            require_once 'Zend/View/Exception.php';
            throw new Zend_View_Exception("You must set an instance of Zend_Translate or Zend_Translate_Adapter");
        }
        return $this;
    }
 
    /*
     * Retrieve translation object
     *
     * If none is currently registered, attempts to pull it from the registry
     * using the key 'Zend_Translate'.
     *
     * @return Zend_Translate_Adapter|null
     */
    public function getTranslator()
    {
        if (null === $this->_translator) {
            require_once 'Zend/Registry.php';
            if (Zend_Registry::isRegistered('Zend_Translate')) {
                $this->setTranslator(Zend_Registry::get('Zend_Translate'));
            }
        }
        return $this->_translator;
    }
 
    /**
     * Enables translation
     *
     * @return Zend_View_Helper_BreadCrumb
     */
    public function enableTranslation()
    {
        $this->_translate = true;
        return $this;
    }
 
    /**
     * Disables translation
     *
     * @return Zend_View_Helper_BreadCrumb
     */
    public function disableTranslation()
    {
        $this->_translate = false;
        return $this;
    }
 
    /**
     * Turn helper into string to echo.
     *
     * @param  string|null $indent
     * @param  string|null $locale
     * @return string
     */
    public function toString($indent = null, $locale = null)
    {
        $indent = (null !== $indent) ? $this->getWhitespace($indent) : $this->getIndent();
 
        $items = array();
        if($this->_translate && $translator = $this->getTranslator()) {
            // Translator is set.
            for($i = 0; $i < $this->count(); $i++) {
                // Loop through all breadcrumb items.
                // Get item and its url.
                $item = $this->offsetGet($i);
                $url = $this->_urls->offsetGet($i);
                if(null === $url) {
                    // No url is set, add an url-less item.
                    $items[] = $translator->translate($item, $locale);
                } else {
                    // Url is set, create HTML.
                    $items[] = '<a href="'.$url.'">'.$translator->translate($item, $locale).'</a>';
                }
            }
        } else {
            // No translation required.
            for($i = 0; $i < $this->count(); $i++) {
                // Loop through all breadcrumb items.
                // Get item and its url.
                $item = $this->offsetGet($i);
                $url = $this->_urls->offsetGet($i);
                if(null === $url) {
                    // No url is set, add an url-less item.
                    $items[] = $item;
                } else {
                    // Url is set, create HTML.
                    $items[] = '<a href="'.$url.'">'.$item.'</a>';
                }
            }
        }
        // Fetch set separator.
        $separator = $this->getSeparator();
        $output = '';
        // Check if a prefix was set.
        if(($prefix = $this->getPrefix())) {
            // Add prefix to beginning of string.
            $output  .= $prefix;
        }
        // Implode all items and append them to the string.
        $output .= implode($separator, $items);
        // Check if a postfix was set.
        if(($postfix = $this->getPostfix())) {
            // Add a postfix to the end of the string.
            $output .= $postfix;
        }
        // Check if escaping is enabled (should be disabled when using urls).
        $output = ($this->_autoEscape) ? $this->_escape($output) : $output;
        // Return the final string with breadcrumbs.
        return $indent . $output;
    }
}

PHP Security – Disabling potentially harmful functions

September 3rd, 2009 No comments

PHP Security – Disabling potentially harmful functions

Most instances of hacked PHP web-servers I’ve seen have been exploited by some hole in an application or some other way to upload bad PHP code. These PHP scripts run malicious code through the PHP functions that execute commands directly on the server. This can easily be countered by disabling those functions.

Just use the disable_functions configuration option in your global php.ini file:

disable_functions = "apache_child_terminate, apache_setenv, define_syslog_variables, escapeshellarg, escapeshellcmd, exec, fputs, fwrite, highlight_file, passthru, php_uname, popen, posix_getpwuid, posix_kill, posix_mkfifo, posix_setpgid, posix_setsid, posix_setuid, posix_setuid, posix_uname, proc_close, proc_get_status, proc_nice, proc_open, proc_terminate, shell_exec, system, eval"

You cannot set the disable_functions through set_ini() (see: http://www.php.net/manual/en/ini.list.php). So the PHP configuration modifying functions can be left enabled without risk. The code above also blocks some other potentially harmful functions.

Categories: PHP Tags: , , ,

How to add a subversion build number to your Xcode project

August 19th, 2009 No comments
Major version and SVN revision number used as build number

Major version and SVN revision number used as build number

Using the SVN revision number can be very useful. For example when publishing beta versions, or just being able to track your builds in more detail.

Create an empty  file called “buildnumber.xcconfig” in you project resource folder.

Double click your build target. Go to the build tab. in the dropdown on the bottom right, select Based On: buildnumber.
Scroll down and under the header Versioning change the Current Project Version to ${BUILD_NUMBER}.

Open your Info.plist file. Add these lines:
<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>CFBundleShortVersionString</key>
<string>Version MAJORVERSION</string>

You can enter anything you want for CFBundleVersion. This will be the major version name.
Now expand your target until you see Run Script. Right click it and go to Add>New Build Phase>New Run Script Build Phase.
Enter this script in the script window and change the project directory to match yours.

export TEMP=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e ‘s/^[^:]*://;s/[A-Za-z]//’`
echo “BUILD_NUMBER = $TEMP” > ${PROJECT_DIR}/buildnumber.xcconfig

After this you should be getting “Version MAJORVERSION (xx)” string in your application’s about window with xx being the current SVN revision. You might need to clean all targets and rebuild your application for the changes to kick in.

Creating and transfering pdb ebook files for use on the iphone/ipod touch eReader application

August 2nd, 2009 No comments

I really love the eReader application on my iPod touch. I think it is the best application that I’ve come across uptill now to read books. But you can’t just drag and drop e-books to your iPhone or iPod touch because apple locks iPhone applications to only their own storage area to store and retrieve data. This is one of the hassles besides converting e-books to the required pdb palm os file format. This is a short post on how to get your e-books from your computer to your eReader application on your iPhone or iPod touch.

The first step is to convert your e-books to the pdb format required by eReader. I use PorDiBle for OS X to convert plain text  (.txt), ms word (.doc), HMTL (.html, .htm) and Rich text (.rtf) formats to .pdb. You can get it here: http://www.loghound.com/pordible/. When installed, just drag & drop the .txt file onto the application icon and it will prompt you to enter the books name. After this the application will convert it to a .pdb file in the same directory and with the same filename as the original. If you want to delete the source file automatically after converting, just open PorBiBle and select preferences from the menu.
But you’ll often have e-books in different formats. For example, the two most important: PDF and microsoft’s lit.
These you’ll have to convert to plain text before you can drop them into PorDiBle. To do that for PDF, just open the file in adobe acrobat reader, and select File>save as text from the menu. To convert lit format to html download a OS X program from this guy: http://hansr.net called lit2html, you can download lit2html here (right click & save as): http://www.hansr.net/Lit2html.dmg. You can drag & drop a lit file to the lit2html application, and it will create a folder containing all components inside the lit file. To convert this e-book to pdb, just drag the .htm file with the title of your book (generally the one with the largest filesize) to PorDiBle.
I’m not aware of any similar applications for windows. If you run windows you’ll have to look for conversion utilities. If you find any good ones, please reply to this post.

Now that you have your .pdb file you are ready to get them to you eReader application. Because the application storage can not be accessed externally you will have to download the e-books from inside the application. To do this you will need to browse to a website, containing links to your books with ereader as protocol. Example: ereader://http://www.somewebsite.com/book.pdb or on a local LAN server: ereader://192.168.1.3/books/book.pdb. You’ll need a web server to do this with your own books. I will not go into the particulars of setting one up on your local machine if you do not have one available. Many, many tutorials exist already for that purpose.
When you have a web server available to you, make sure it supports PHP scripts. I’ve created a PHP script that will automatically create a web page containing eReader links to all files in the directory where the scripts reside. The only thing you will have to do is create a directory on your web server (named ebooks for example) containing this script in a plain text file with the filename “index.php”. You can download the script here (right click, save as): http://weblog.oxidiser.nl/wp-content/uploads/2009/08/index.phps. Just rename the file from index.phps to index.php. You’re all set to download e-books into eReader after you’ve uploaded this file to your directory. The only thing left is drop in your pdb e-book files into this same directory. Just browse to this folder in safari on your iPhone or iPod touch (if you choose the directory e-books in the root of your web server it will be http://yourserver/ebooks). You will get a list with filenames of all the e-books currently in the ebooks folder. When you tap one, it will automatically start the eReader application and download the e-book into it.

That’s it! Now you have your e-book on your device ready to be read!

Garmin Edge 605 GPS enabled bike computer (review)

July 3rd, 2009 No comments
Garmin edge 605 GPS enabled bike computer on my mountainbike

Garmin edge 605 GPS enabled bike computer mounted on my mountainbike

I usually cycle routes that are familiar to me because I know the way, so I can ride without stopping. But I wanted something more than that. I wanted a simple but useful device to go on unfamiliar bike rides with, without getting lost or stopping to look at a map.

Some things I decided I would need where:

  • Size, as small as possible.
  • Weight, as light as possible.
  • Long battery life.
  • Display should be easy to read in bright daylight and at night.
  • Water proof for obvious reasons.
  • Easy to use.

So I choose and bought a Garmin 605 GPS enabled bike computer a few weeks back. This unit has all the traits in the list above. It comes with two mounts. One for horizontal and one for vertical bar mounting. Those are attached with supplied tie-wraps. The mount is very stable and I’m not worried about losing the device. Even if it is a rough road (or no road at all).
I’ve used it to ride some routes and it works pretty well. It’s hard to operate the device when the road is rough, but that is expected. I’ve used it in the rain once now and have not had any problems. It’s water resistance rating is IPX7, which means it should survive temporary immersion in up to 1 meter of water for an hour. So I’m not worried about rain. The display readability is excellent. You don’t need the back light at all during the day and this improves the battery life considerably. At night the display lights up if you touch a button, or when it gives a new direction for you to take. You can set both the brightness and how long it should stay lit. You can also enable beeping sounds when the device wants you to change direction. Battery life is pretty good. The specification mentions battery life of up to 16 hours. I don’t know if this is true but I’ve never been without power up till now.

I’ve found a very useful website where you can find routes by category (car+motorcycle/cycling/hiking) and place by looking at a map. You can also create an account and create your own routes to share with others. The website and first route I have made can be found here:  routeyou.com.

I’ve even tested it with large routes and tracks with many thousands of points of up to 250km. It loads them very slowly, but it works. I will test this on a motorcycle trip later on. I hope the device will be usable on the motorcycle as well. I’ll update this post after the trip and let you know if it worked good enough for motorcycle use.

I think this device was worth my money. I can go out biking without worrying about getting lost. Also, planning routes before you go riding is fun, and you can create a route that seems most interesting to you.

Where to get new inspiration for your photography

June 17th, 2009 No comments

Where to get new inspiration for your photography?

It just happens sometimes. It’s nice weather outside and you want to go out to take pictures, but you’re fresh out of ideas. I’ve created a small list of subjects from which you could get some inspiration or ideas to get out and do something when you’re out of ideas. Use your imagination when you read through the list and that cool idea might just pop up into your mind.

  • Reflections
  • Movement
  • Water in movement
  • Twilight
  • Sports
  • Hip Shots
  • Shadow/light
  • Night
  • Landscape
  • Cityscape/urban
  • Food/eating
  • Rhythm/repetition
  • Chaos
  • Symmetry
  • Transparency
  • Bridges
  • Animals
  • Architecture
  • Church
  • Religion
  • Silhouette
  • Faith
  • Burial grounds/memorial/cemeteries
  • Death
  • Decay
  • Abandoned
  • Vandalism
  • Steel
  • Glass
  • Graffiti/street art
  • City macro (details of city life)
  • Time
  • Flight
  • Emotion
  • Simplicity
  • Fire/flame/smoke
  • Seasons (winter, spring, summer, autumn)
  • Creepy crawlies
  • Tonal perspective
  • Size perspective
  • Birds eye perspective
  • Frog perspective
  • Vantage point perspective
  • Shape (square, round and so on)
  • Color (red/green/blue and so on)
  • Vanishing point