If you import unicode text into latin1 database column, the symbols would be screwed up — russian symbols become a shit like “залоговый депозит”.
It’s handy to use in Zend FW driven project. For example, you want to make an in-place tracker (e.g. Google Analytics) — you create a helper class My_View_Helper_Tracker inherited from Zend_View_Helper, Zend finds its automatically and then you are free to use your helper method:
echo $this->tracker( $trackerID );
The question is what you gonna do if you want a base class for a family of trackers?
It’s not so obvoius due to naming conventions.
Let’s say you want 2 kinds of trackers: Google Analytics and Euroads.
1. You create such files structure:
library
- My
- View
- Helper
- Tracker
Abstract.php
- Google
Page.php
- Euroads
Owner.php
Guest.php
During my work on SunnyRentals I’ve got a task to add 2 closest airports to every property an owner creates.
I implemented it quite fast since we have a database of airports with coordinates.
While playing with this feature, we found out that it is not good enough — the real task must be to add 2 closest and biggest airports. The problem is that we don’t have any data in airports DB to guess how big or famous a particular airport is.
So we need to rate every airport somehow…
The solution we found was simple — we need to google for the airport name and get the search results count. The count can be considered as rating value — London Heathrow airport has 2.33 million results while Kiev Zhulyany airport has only 0.77 mln which looks fair.
Several things to pay attention to:
the query we formed was [city name] + [airport name] + ‘ airport’
if this query gives zero result, I omit the city name — at times it hepls
we put the query into quotes to google for the exact phrase, otherwise the London City airport gets the highest rating due to the fact that “city” is a general term
if the airport name includes the city name (Melbourne Intl), we omit the city name — ”Melbourne Intl airport” is better then “Melbourne Melbourne Intl airport“
in addition to previous idea — if the airport name sounds like the city name, we omit the city name as well. Example: Narsarsuaq airport in Narssarssuaq city. I used soundex function for this comparison — it’s present in PHP and MySQL.
Are you aware of Federated engine in MySQL (apart from MyISAM and InnoDB)?
This engine allows you to define a table that sucks data from another table, even from a remore server. The tables definition must be the same.
I use it for the following:
Every time I rebuild the project, I have wait for 15 minutes while two big tables are created and filled with data — these are geo data tables (world cities, regions, etc), 4 mln records, and POI table, 2 mln records. I use Federated tables to create two separate databases and just link these tables in my project.
These tables are shared between several environments (dev, test and live) on the same server.
To check if your MySQL server has the Federated engine supported, you can use just a phpMyAdmin — go to home page of you phpMyAdmin installation (click Home picture), then choose Engines tab and check there.
If it’s not enabled (gray), open your my.ini file, find the “[mysqld]” part and make it to look like this:
[mysqld]
federated
P.S. If you have an error in the table definition, phpMyAdmin shows your database as empty. To fix this, log in via mysql console and try to make a SELECT from this poorly defined table and you get the error message to work with.
Now let’s create a SQL function for handy converts. Create a udf.sql file and add this in it:
DELIMITER //
DROP FUNCTION IF EXISTS EXCHANGE;
CREATE FUNCTION EXCHANGE( amount DOUBLE, cFrom CHAR(3), cTo CHAR(3) ) RETURNS DOUBLE READS SQL DATA DETERMINISTIC
COMMENT 'converts money amount from one currency to another'
BEGIN
DECLARE rateFrom DOUBLE DEFAULT 0;
DECLARE rateTo DOUBLE DEFAULT 0;
SELECT `rate` INTO rateFrom FROM `currency` WHERE `code` = cFrom;
SELECT `rate` INTO rateTo FROM `currency` WHERE `code` = cTo;
IF ISNULL( rateFrom ) OR ISNULL( rateTo ) THEN
RETURN NULL;
END IF;
RETURN amount * rateTo / rateFrom;
END; //
DELIMITER ;
and run this command in your shell:
mysql --user=USER --password=PASS DATABASE < udf.sql
This is how you can use this function — how to convert 10 US dollars to Canadian dollars:
SELECT EXCHANGE( 10, 'USD', 'CAD')
which results in $10 = 10.93 Canadian dollars.
P.S. Consider adding the currency export action call to your cron scripts.
P.P.S. A function to unzip the data file can be got at
A problem comes on stage when a Flash file uploader is added to your project – usually it cannot “login” to your site, i.e. users are not able to use the Flash file uploader behind beta login.
That’s how I solved it.
It’s not the web server who must solve this (Apache), it’s the application server (PHP). So remove the lines above from .htaccess and use for this purpose — it’s Zend’s HTTP Authentication Adapter.
What concerns the Flash uploader: it sends ‘Shockwave Flash’ as value of ‘User-Agent’ request header. So in your Initializer or Bootstrap file (where you load Zend_Auth_Adapter_Http) check this header value, and if it’s not Flash’s, go for HTTP authentication.
P.S. Hackers can assume this and fake the header to access your site. To cope with that, use an additional secret request variable (Flash uploaders allow this) and check it at server side.
Reverse Geocoding is process opposite to Geocoding (when you get map coordinates by city/country given). So the idea is to get city name by coordinates on the map.
Why you may need it? For example, user is supposed to add a marker on the map, and you want to check that the marker is within a particular country or region.
Solutions:
(JavaScript) can work with coordinates to retrieve location name. Advantage is that return information is translated to the preferred language of your browser. Here is you can play with.
offers several services, among which you can find Reverse Geocoding web service (REST or JSON) which can work with coordinates and postal codes. Advantage — you can download city/region/country names and POI with coordinates.
Data feeds often come in XML format, so your application must be able to deal with that format.
As I already wrote, data in CSV format (comma separated values) can be loaded to database extremely fast. So my idea was to convert XML data files to CSV and then use bulk load to database. My tests shown that this is faster in 10-100 times than one by one inserts.
Yesterday I decided to write a generalized solution for this, and it turned out that there is no need: it’s just coming — MySQL 6 will have such feature!
How it works: you create a table, name its columns exactly as XML nodes/attributes names or — and MySQL server will load it correspondently.
Example — you downloaded a POI list file (Points of Interest) called poi.xml that looks like this:
CREATE TABLE IF NOT EXISTS `poi` (
`lat` varchar(255) NOT NULL,
`lon` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL
) DEFAULT CHARSET=utf8;
OK, now you load the XML data to your table:
LOAD XML INFILE '\\path\\to\\poi.txt'
INTO TABLE `poi`
ROWS IDENTIFIED BY '<wpt>'
Voila!
The good thing is that MySQL 6 is already available in alpha version — good enough for development purposes; I gave it a try — it takes 5 seconds to load 4.8 Mb of data in 19 files.
You have a web application hosted on a server and you want to set file access permissions by chmod command, different for files and folders.
Why different? A folder must have ‘x’ (access) flag:
drwxr-xr-x
At the same time a file shouldn’t have it (otherwise it would be executable):
rw-r--r--
How can you set it up for all nested files/folders in your application folder?
You can solve this task by setting common persmissions for all files and folders (step 1) and then make folders accessable (step 2), recursively:
chmod -R 644 .
chmod -R a+X .
But chmod allows you to set up only access flag for folders, you cannot set one persmission for folders and another for files.
Here is a script written by my collegue Anton [vojtoshik] Voitovych to solve this task.
Copy it and save to a file (I saved it in /bin/rchmod — thus it’s accessable for all users of my system):
#!/bin/bash
files="0644";
directories="0755";
path=$1;
shift;
while getopts "d:f:" OPTION
do
case $OPTION in
f) files="$OPTARG" ;;
d) directories="$OPTARG" ;;
esac
done
if [ "$path" != '' ]; then
find "$path" -type d ! -name "." -exec chmod "$directories" {} \;
find "$path" -type f -exec chmod "$files" {} \;
else
echo "Usage: rchmod <path_to_directory> [-d <directories mode>] [-f <files mode>]";
echo -ne \\n;
fi
OK, now make it executable:
chmod 755 rchmod
How to use it.
1. You are in your application folder and want to set 755 (drwxr-xr-x) mode for folders and 644 (rw-r--r--) mode for files which is the default:
rchmod .
2. You want to set 123 permissions only for folders in a particular folder::
rchmod /some/path/to/folder -d 123
3. You want to set 123 permissions for folders and 456 permission for files in a particular folder::
rchmod /some/path/to/folder -d 123 -f 456
Note: don’t forget that every time after that command run you should make some folders writable (wp-content/uploads, cache, temp — what else you have in your webapp).
After authentication in my project it takes about 10-20 minutes for the auth session to expire, which is not handy — you go to get a snack and see a login screen coming back.
This is how to make the TTL of your auth session longer:
Recent Comments