Archive for the ‘PHP’ Category

Create Remote Login for Typo3

Recently, I wanted to add the possibility to log directly into Typo3′s backend from some other PHP application without entering the password again. The reason for this was mainly convenience since typing in two different logins (or worse: the same login twice) seems annoying.

Of course, a lot of other people have already done the same thing, so I read around in some blogs/forums…the usual. Most posts pointed out that you need to write a Typo3 backend extension which would do that task for you.

Since I was too lazy to do so, I looked around a bit in the database and the code and came up with a solution which sometimes works and sometimes not…more on that later.

First of all, there was the issue of obtaining the backend user-ID which is stored in the table be_users. You can query that database with anything you got on a user, I used the e-mail address:

SELECT
  `uid`
FROM
  `be_users`
WHERE
  `email`=:email
LIMIT 1;

This is of course done without checking the password. Now the next thing that should be done is to remove all logins, which the following query does:

DELETE FROM
  `be_sessions`
WHERE
  `ses_userid`=:userId;

Typo secures its sessions in several ways, the most tricky one of them is by calculating a hash out of the browser’s user-agent. I believe this one is likely to change in future versions (the original code looks like there could be some additions), but here’s the code that does the magic for the current 4.4 release:

$hashLock=hexdec(substr(md5(":".$_SERVER['HTTP_USER_AGENT']),0,7));

Ok, now with that information (plus a random $sessionId you need to generate), the new session can be created in the database, here’s the query:

INSERT INTO `be_sessions` (
  `ses_id`,
  `ses_name`,
  `ses_iplock`,
  `ses_hashlock`,
  `ses_userid`,
  `ses_tstamp`,
  `ses_data`,
  `ses_backuserid`
) VALUES (
  :sessionId,
  'be_typo_user',
  :userIp,
  :hashlock,
  :userId,
  UNIX_TIMESTAMP(),
  NULL,
  0
);

The last part is to push the cookies to the client, and here lies the most important challenge. By default, Typo locks all cookies to the URL of the backend. However, if no cookies were present yet, one can create & send cookies which are accepted by Typo. First, here’s the code to create the cookies (assuming the backend is located at /typo3, also the cookies here are locked to a SSL-connection):

setcookie("be_typo_user",$sessionId,0,"/typo3/",$_SERVER['SERVER_NAME'],true);
setcookie("typo3-login-cookiecheck","true",0,"/",$_SERVER['SERVER_NAME'],false);

Conclusion

Now in my short tests, the above system always worked when there were no Typo3-generated cookies present yet. So if you want this method to REALLY work, you need to place the script within the same directory as the Typo3 backend so you can write the correct cookies, and you might want to make sure no cookies remain by deleting them first.

So all in all, this method was just a quick hack and currently fits my needs, the better approach is certainly to create an auth extension.

Mysqldump and Error “Unknown command ‘\0′”

When you’re using mysqldump to put a complete database into a textfile and try to import that file into another MySQL server, you might come across the error message “Unknown command ‘\0‘” on importing the database.

The most probable cause to this is a database which contains (large) blobs, as they somehow might not get encoded to the right format.

Easy solution to this problem: Use the –hex-blob option:

mysqldump -uusername -p --hex-blob db_name > db_name.sql

This will force mysqldump to encode all blobs in binary format, which won’t get messed up in encoding problems.

Typo3 and UTF-8 support

There are quite a few configuration options in Typo3 which come into play if you intend to run the system completely with UTF-8. And the mean thing is: If you sod up only one of them, chances are good that some things will work but others won’t.
So here’s a list of options I’m currently setting for UTF-8 support.

Settings in localconf.php

The following values need to be set in localconf.php, so you can just set them using the Typo3 install tool.

forceCharset

The value of this field is used by Typo internally for different configuration. You need to set it to UTF-8.

multiplyDBfieldSize

This value sets the size of characters as used in the database. Since in UTF-8, only one character is used, you need to set this to 1 (this is the default).

setDBinit

All statements placed within this value will be sent to the database server each time a new connection is opened. The following two lines should be sufficient to do the magic, if not, set the character_set_server as well:

SET NAMES utf8;
SET CHARACTER SET utf8;

UTF8filesystem

With this field, you tell Typo that your filesystem supports UTF-8 filenames. This is quite important, otherwise Typo will place uploaded files with non-ASCII-characters under invalid names. Set to 1.

If you don’t like the install tool, here’s the PHP code to put into your localconf.php:

$TYPO3_CONF_VARS['SYS']['UTF8filesystem'] = '1';
$TYPO3_CONF_VARS['BE']['forceCharset'] = 'utf-8';
$TYPO3_CONF_VARS['SYS']['setDBinit'] = 'SET NAMES utf8;'.chr(10).'SET CHARACTER SET utf8;';

Settings in TypoScript

In order to have Typo deliver the page with a valid encoding head, you should also add the following statement in your template.

config{
  additionalHeaders = Content-Type:text/html; charset=utf-8
  metaCharset = utf-8
}

From now on, Typo will use UTF-8 as the default charset on all levels.

Backticks in MySQL

I’ve always wondered, why software such as phpMyAdmin uses a pair of backticks around every table- or column-name, while you read a lot of SQL-statements that don’t.

The answer is quite simple and you’re likely to run into this issue sometime, if you’re creating a lot of MySQL-queries. Take the following (fictional) table name, for example:

Table-1

This is a valid table name in MySQL, so now let’s take a look what’s inside. You’re probably using a statement like:

SELECT * FROM Table-1;

And bang, you’ll get something like: “You have an error in your SQL syntax“. Why is that? If you take a closer look, you’ll see that the syntax is ambiguous. The parser does not understand if you want to reference the table named Table-1 or if you want to subtract 1 from the column named Table.

So to clarify things for the database engine, you must use a pair of backticks, which will escape all special characters contained within them:

SELECT * FROM `Table-1`;

By the way, the same rules apply if you have any other databases, tables or columns named with reserved keywords. A more classic example is to have a column named max or min (both MySQL-functions).

If you’re lazy, you can only add the backticks at the necessary places, for a more consistent look, you might as well add them everywhere. I’m not sure if this is part of any SQL-Standard or if it’s just MySQL specialty.

Exposed PHP session files

Today, I was searching for how phpMyAdmin converts BLOB-strings to hexadecimal ones (which is accomplished with bin2hex(), by the way), so I looked around using the searchterm “sql_hex_for_blob“.

What I was looking for: An answer as to how the conversion is made.

What I got: PHP session files.

There are actually some servers on the net, which expose their session.save_path-directory open to every viewer and even have directory listings turned on. And of those servers, some don’t even set the access rights in a way, that will disallow viewing. This is interesting in two ways:

  1. The session files might contain some sensible data (depending on the application using them),  phpMyAdmin for example saves the query history within them. Attackers have a really good insight into the DB structure to perform SQL injection.
  2. Even if the files are not readable themselves, the filename contains the session ID. As far as I know, PHP doesn’t check for the IP address, this means attackers could potentially take over a running session.

I haven’t really worked out a Google query yet to search for these files, but I guess someone already has…

Update

I’ve looked around some more and haven’t figured out a query that will gather all session files. But just take a variable name, which is part of the session data of some widespread PHP app (e.g. phpMyAdmin) and you’ll find lots of session files on Google.

Fixing fatal PHP error “Exception thrown without a stack frame in Unknown on line 0″

Have you ever seen the message “PHP Fatal error:  Exception thrown without a stack frame in Unknown on line 0″ and just couldn’t figure out what was causing it?

I’ve seen this message lots of times, but never really tried to find out the cause, instead I always patched the problem somehow without really understanding what this message means. Turns out, the answer is quite understandable :)

While PHP will maintain a stack trace for each exception thrown in “normal” operation mode, there are certain times, when the environment isn’t capable of doing that. Here are two popular examples, which I both ran into a lot without knowing:

  • Throw an exception within a custom exception handler: When you’re using a custom exception handler, make sure that you do NOT throw an exception inside. This does not work, as PHP is not in normal operation mode while processing an exception. As someone pointed out in the comments for setting a customer exception handler, you can place every line of code of your custom exception handler inside a try-catch-block, dump the exception to error_log() and remove the cause for the exception later on.
  • Throw an exception within a constructor or destructor: If you throw an exception in a constructor, the class will not be constructed properly, thus resulting in an invalid state. Likewise, if you do the same in a destructor, the class might have already been partially destructed. The solution I opted for on this issue is the same as above: Place the code of every con-/destructor inside a try-catch-block. If you don’t do this, be sure that no functions you call from con-/destructors will ever throw an exception.
  • Throwing an exception in any autoload function: I’ve had the same behavior when I tried to throw an exception in any function that got registered with spl_autoload_register(), although half of the time it did work.

I’m sure there are a lot of other causes for this error, if I ever see another one, I’ll update this post.

Show only excerpts of blog posts on WordPress startpage

If you would like WordPress to show only the excerpts of articles on the startpage, here’s a possible solution:

Change into the folder of your template and open the index.php file. Now look for the function named

the_content(...)

and simply change it to

the_excerpt(...)

without touching the inner arguments. That’s it, from now on, only the excerpts of each article will be displayed on your startpage.

PHP serialization and MySQL

I’ve had a problem today which was driving me nuts: Whenever I read out some serialized PHP data from a MySQL database, the unserialize() function refused to deserialize the data. When manually putting the same set of data into a textfile and reading it via file_get_contents(), the problem did not occur.

I did not exactly figure out, if the problem were the German Umlaute, which where contained within the text, in combination with a wrong DB charset, or some other character problems. Anywho, the comments at php.net finally set me straight: I encoded the data with base64_encode() before sending it to the database, reversing the stacking of functions in read operations.

Another problem is the fact, that unserialize() will return false if the deserialisation was unsucessfull, thus leaving you no chance to discriminate between a deserialization error and a correctly decoded false value. The following decode function also addresses that problem.

For your convenience, I’ve attached the two functions I used for de- and encoding:

/**
  * Internal function to put variables into a format which
  * can be stored in the database.
  * As a basis, serialize() is used, for storage
  * in SQL database, the  values are then base64 encoded
  * @param mixed $value The value to encode, needs to be processable by serialize
  * @return string Representation of value to use in database
  */
public function encodeValue($value){
    return base64_encode(serialize($value));
}
/**
 * Opposite of <em>encodeValue()</em>. This will also check, if deserialization
 * has worked, throwing an exception if not
 * @param $encodedValue String in format provided by <em>encodeValue()</em>
 * @return mixed The original value
 * @throws Exception If deserialization did not work.
 */
public function decodeValue($encodedValue){
    $decodedValue=base64_decode($encodedValue);
    $unserialized=unserialize($decodedValue);

    //check for faulty serialization
    if(unserialize($decodedValue)===false && $decodedValue!=serialize(false)){
        throw new Exception("Error while deserializing this: $decodedValue");
    }

    return $unserialized;
}
Return top