Setup of Mercurial server with cPanel – the easy way

Posted: March 23rd, 2012 | Author: | Filed under: General | No Comments »

Mercurial is a cross-platform, distributed revision control tool for software developers. In this article will be presented a handy way to install and configure Mercurial on a server with cPanel . All operations presented will only need a standard FTP/SSH access to a user account, except the initial installation of the Mercurial RPM which needs root rights.  This installation procedure is very suitable for those creating websites and wanting a quick solution to track the changes in their source code using a repository stored right next to the website.

 

The information below were compiled from several sources with some modifications to suit the above needs.  The aim is to use only cPanel and SSH with user rights (e.g. no root required !)  and have a repository ready in 5 minutes.  The repository will then be accessed securely as hg.yoursite.com

 

Intial preparation:   install the Mercurial package as root http://mercurial.selenic.com/wiki/HgWebDirStepByStep

Here is a sample installation from a RPM on an OpenSuse linux:

 wget http://download.opensuse.org/repositories/devel:/tools:/scm/openSUSE_10.2/x86_64/mercurial-1.0-1.2.x86_64.rpm
$ sudo rpm -ihv mercurial-1.0-1.2.x86_64.rpm

 

Step 1.  Create subdomain

Login in cPanel and create hg.yourdomain.com.  Do not create the directory under /public_html  so the repository won't mix with the files of the website

 

Step 2. Create the configuration file of the repository

Use a FTP client and navigate into the directory of the subdomain. Create a folder for your repo, i.e. projectrepo . Use some name other than the one you want to access the repo with because later there will be some URL rewiting rules added into a .htaccess file which won't work otherwise.  In this example the repo url will be made as hg.yourdomain.com/project

Continue navigating into cgi-bin where two files has to be be uploaded: hgweb.config containing the repository configuration and hgwebdir.cgi containing the code needed to run the repository.  Create the two files on your computer and upload them into /cgi-bin:

/cgi-bin/hgweb.config

[paths]
#VIRTUAL_PATH = /REAL/PATH
project = ~/hg/projectrepo

/cgi-bin/hgwebdir.cgi

#!/usr/bin/env python
from mercurial import demandimport; demandimport.enable()

import cgitb
cgitb.enable()

import os
os.environ["HGENCODING"] = "UTF-8"

from mercurial.hgweb.hgwebdir_mod import hgwebdir
import mercurial.hgweb.wsgicgi as wsgicgi

application = hgwebdir('hgweb.config')
wsgicgi.launch(application)

Change the attributes of hgwebdir.cgi to be executable (0755).  This can be made within the FTP client (at least TotalCommander implements it and probably many other such applications have that option. It is under Files->Change attributes).

 

Step 3. Initialize repository

Using a SSH console go into the ~/hg folder and run these commands:

hg init

find . -type f -exec chmod 0666 "{}" \;

find . -type d -exec chmod 0777 "{}" \;

 

The last two commands are needed when the web server (Apache) runs the scripts under a different user than the owner of the account.  In order to create files and folder full write rights are needed for user apache or nobody.

A configuration file will have to be created and uploaded into the new repository. For this , create a file named hgrc with the following content:

~/hg/project/.hg/hgrc

[web]
description = My repository
push_ssl = false
allow_push = john

# enable snapshot downloads
allow_archive = gz zip bz2

baseurl = /

In this configuration the ssl is disabled which may be a security problem. If your host allows https connections then you may set this to true later. However, the repository is protected through HTTP Basic authentication – see below.

Upload the file above under ~/hg/project/.hg/

 

 Step 4. Secure the repository

Create a .htaccess file with the following content for uploading in the root of your subdomain:

~/hg/.htaccess

# Taken from http://www.pmwiki.org/wiki/Cookbook/CleanUrls#samedir
# Used at http://ggap.sf.net/hg/
Options +ExecCGI
RewriteEngine On
#write base depending on where the base url lives
RewriteBase /cgi-bin
RewriteRule ^$ hgwebdir.cgi  [L]

# Send requests for files that exist to those files.
RewriteCond %{REQUEST_FILENAME} !-f
# Send requests for directories that exist to those directories.
RewriteCond %{REQUEST_FILENAME} !-d
# Send requests to hgwebdir.cgi, appending the rest of url.
RewriteRule (.*) /cgi-bin/hgwebdir.cgi/$1  [QSA,L]

The rules above allows accessing the repository with an url like hg.yourdomain.com/project instead of hg.yourdomain.com/cgi-bin/hgwebdir.cgi/project and is a replacement for the original procedure described in the Mercurial documentation where one has to modify httpd.conf, as root.

Finally, password protect the repository within cpanel. The operations below will update .htaccess, adding the necessary lines for basic authentication:

 

Finish

Access your repository within a browser with an URL like:

http://john:sompassword123@hg.yourdomain.com/hg/project

Use the URL above in your Mercurial client too.

 

 Referrences


Postfix with DKIM, Domainkeys, SPf and Sender-ID

Posted: April 3rd, 2010 | Author: | Filed under: Server side | Tags: , , , , | 9 Comments »

The authentication methods are a great tool for fighting against spammers and every server admin should have it implemented on their systems. But since it is not that simple to configure them, they often prove to be a headache with not enough documentation available. I had to pay myself the tribute (in hours spent) for making the system work in the configuration I wanted and for the others having the same problems here is my story.My configuration is : CentOS 5, Postfix 2.3.3

The server is running some websites and I wanted to be capable of sending signed emails within PHP and also using some email client through SMTP. Since there are more than one website I wanted also a simple way to add/modify domains in the filters' configuration.

Whenever I write "domain.tld" you should use your own domain name (mysite.com, wikitiki.org, etc)

The tools I installed are listed here under the Authentication section. They are:

  • dkfilter - a SMTP-proxy signing filter. Quite easy to install but, as the author says, it is good for sending authenticated email served by the port 587 not 25 which is why I give up on it. My server must be able to send emails from PHP and act as a SMTP mail server for another server.
  • dkim-milter – DKIM signer/verifier (http://sourceforge.net/projects/dkim-milter/)
  • dk-milter – Domainkeys sender/verifier. (http://sourceforge.net/projects/dk-milter/) Pay attention to these names because it is a lot of confusion because not only DK and DKIM sounds alike but their executable are called "filters": dkim-filter and dk-filter. Couldn't be much more complicated for newbies.
  • sid-milter – Sender ID verifier. Note that it's a verifier only ! (http://sourceforge.net/projects/sid-milter/)

1. DKIM

Installing dkim. For this follow one of these links:

How to Setup DomainKeys Identified Mail (DKIM) with Postfix and Ubuntu Server

Setting up DKIM, SPF, Domainkeys DNS, Regular DNS on CentOS 5.3

I won't go through the installation steps you can read about in tutorials as above. Instead I will focus on what should be checked, customized, verified so that will help in custom installations or troubleshooting.

So, for the installation I will focus on:

subject value description
username/usergroup domainkeys.domainkeys This is the owner of the signer/verifier processes. Doesn't matter the names but once created will be used for all filters
folders for configuration /etc/mail/dkim/
/etc/mail/domainkeys/
These must be owned by the user above. When adding new domains I have to modify some files here
initialization scripts /etc/init.d/dkim
/etc/init.d/domainkeys
/etc/init.d/sender-id
Essentially is the same start-up script configured for each filter. Good to know where they are when testing the configuration
folders for private keys /var/db/domainkeys/domain.tld/ These must be owned by the user above. Here I'll place the private keys
folders & files for processes' PIDs /var/run/dkim-milter/pid
/var/run/dk-milter/pid
/var/run/dk-milter/pid
These also have to be owned by the user above. The filters will create/remove the "pid" files as they need

OK, so here there are some background information. DKIM and Domainkeys uses two DNS records and a private key to sign the emails. The DNS records are

  1. policy record. It is defined as a TXT record :
    _domainkey.domain.tld IN TXT "t=y;o=~"

    t=y means the domain is in test mode. When everything works it can be changed to "n"

    o=~ means that some emails will be signed. "o=-" means that all domains are signed

  2. selector record. Also a TXT record storing the key and other parameters:
    default._domainkey.domain.tld IN TXT  "g=*; k=rsa; p=MIGfMA0...ABC"

    "default" is the selector name and will be the same as the one used for generating the keys – see below

    "_domainkey" is a keyword preceding the domain name

    "k=" key type. Optional. Default is rsa

    "p=" public key data.

    "g=" granularity of the key. Optional, default is "*"

    "v=DKIM1" version. It is recommended but I got some errors when I tried to use the same record for Domainkeys because it is defined for DKIM only so I did not use it.  Here is the yahoo tool I tested with

Note: in the two dns records above I used "domain.tld" only because my external nameserver service required it in its web interface. If you own the namesever you will probably not use it as will be appended automatically by named/bind

Important : the server may sign ALL emails with its own domain name or may sign it with other domains but in this case all other domains must have the two DNS records maintained. I went for the first option.

Generating the keys

there are three ways to generate them:

  • online Domain Key / DKIM Key Generation Wizard
  • basic:
    openssl genrsa -out private.key 1024
    openssl rsa -in private.key -out public.key -pubout -outform PEM
  • script included with the dkim:
    dkim-genkey -r -d domain.tld

The result will always be two files, one private key to copy into /var/db/domainkeys/domain.tld/default and one to use it in the DNS record as value for "p=" parameter. Pay attention that I used "default" as filename for the private key in order to use that file for a selector named "default" and defined as such in the DNS record. It is possible to have different selectors which would handle different emails or domains and so I can have:

/var/db/domainkeys/domain.tld/m1.pem – this is created for the selectod m1 and I added an extension just to remember it is a private key file. the extension, if exists, must be "pem" or "private".

/var/db/domainkeys/otherdomain.tld/default – this one will serve emails for another domain with another selector named "default"

The init script

The init script will start|stop the filter and there is where I put the command to do that. It may have two forms, either with the configuration given as parameters to the executable app or with it uses a single parameter which points to a configuration file containing all settings. I used the 2nd option:

COMMAND="dkim-filter -x /etc/dkim.conf"

Then I put in the dkim.conf file all the configuration parameters I needed. Don't forget to make it readable by the user defined above (domainkeys). Some of the most important parameters I put there are:

KeyList                 /etc/mail/dkim/keylist
MTA                     MSA
Selector                default
UserID                  domainkeys:domainkeys
Socket                  inet:8891@localhost

Don't forget that the port numbers will be used in your /etc/postfix/main.cf file:

smtpd_milters = inet:localhost:9967,inet:localhost:8891,inet:localhost:8892
non_smtpd_milters = inet:localhost:9967,inet:localhost:8891,inet:localhost:8892
milter_protocol = 2
[[code]]czozMDpcIm1pbHRlcl9kZWZhdWx0X2FjdGlvbiA9IGFjY2VwdFwiO3tbJiomXX0=[[/code]]

I have here 3 filters, dkim, domainkeys and sender-id, each on its own port. You will find below the entire configuration file I created.

The keylist file

the keylist file contains the relation between the sender-pattern, the signing domain and the path to the private key. I use this keylist file in order to manage easier the domains on my webhost server. For a singe domain one would only use the dkim's configuration file. My keylist file's location is defined in the configuration :

KeyList /etc/mail/dkim/keylist

And contains :

*:domain.tld:/var/db/domainkeys/domain.tld/default

..meaning: all emails (*) will be signed with the domain "domain.tld" using the private key from the file "/var/…/default".

The selector used in  the signature will be the filename portion of  keypath. If the  file referenced by keypath cannot be opened, the  filter will try  again by appending ".pem" and then ".private" before giving up. (man dkim-filter.conf)

Useful commands, part I

  • postsuper -d ALL

    Delete all mail queue. Sometimes due to too many unsent emails the logs are filled in continuously by the emails in queue. For a clean start it's good to have an empty mail queue. Be careful on a production server (you may just ignore it)
  • mail myaccount@yahoo.com

    Send emails from command line. good for a quick test. Verify the results on a yahoo account for both DKIM and Domainkeys
  • telnet localhost 25
    EHLO domain.tld
    MAIL FROM: root@domain.tld
    RCPT TO: myaccount@yahoo.com
    data
    bla bla
    .
    quit

    This is a suite of commands to test sending email through SMTP. Or you can use an email client set for sending through SMTP protocol
  • php -r "mail('myaccount@yahoo.com','test mail','bla bla','From: root@domain.tld');"

    Let the email be sent within PHP. This will test PHP mail() configuration

    A note here: At a certain point my mail sent from PHP was not signed with Domainkeys, only with DKIM. After several tests I found that the $headers in my php script were using Windows separator for new like (\r\n) instead of Linux (\n). I never thought it matters in headers !

  • Online tools: DomainKey Implementor's Tools and Library for email servers & clients especially "DomainKey Policy Record Tester." and "DomainKey Selector Record Tester."
  • tail -f /var/log/maillog

    this is where I look for errors

2. Domainkeys

As above, start with the download & installation from the given links from sourceforge or with the ones below:

Quick And Easy Setup For DomainKeys Using Ubuntu, Postfix And Dkim-Filter

man dk-filter – DomainKeys filter for sendmail online version of the man page for dk-filter

The DNS records follows the same rules as the DKIM above. In fact both DKIM and Domainkeys will use the same DNS records

The init script

The dk-filter does not support all parameters supported by DKIM and especially the one which would allow me to put all configuration in one file therefore the command from this initialization script has all parameters in one line:

COMMAND="dk-filter -u $USER -p inet:$PORT@localhost -l -P $PIDFILE -d $DOMAIN -S $SELECTOR -c simple -k -s $KEYFILE -i $IFILE -m $SUBMISSION_DAEMON -D"
Parameters:

  • -u userid it runs under
  • -p socket to be used by the filter for allowing connections from postfix. It must use a different port number than dkim (of course)
  • -l log calls to syslog
  • -P pidfile – the file used to write the process ID into
  • -d domain list or path to a file containing the domain list one per line (wildcard * allowed in the domain name )
  • -S selector, the name of the selector to be used
  • -k Causes -s to be interpreted as the location of a key list
  • -s keyfile or keyfilepath. Since -k is used this one will be a path to my keyfile (/etc/mail/domainkeys/keylist)
  • -i a file of internal hosts whose mail should be signed rather than verified (/etc/mail/domainkeys/ilist)
  • -D Sign subdomains too

The content of the keylist (differs from DKIM's !):

*@domain.tld:/var/db/domainkeys/domain.tld/default

The ilist contains some IPs (local network's):
192.168.1.0/24127.0.0.1

Note that I am using "/etc/mail/dkim/trusted-hosts" as value for the -d (domain) parameter. This is a path pointing to a dkim folder because I want to make as little changes as possible when adding or removing a domain so I use it for both filters.

The keylist file

This is another small difference than the DKIM's keylist file content. It looks like this (/etc/mail/domainkeys/keylist) :

*@domain.tld:/var/db/domainkeys/domain.tld/default

Each line is in the form "sender-pattern:keypath" where sender-pattern is compared against the sender and keypath is the path to the private key file. The filename portion of this keypath is also the selector name

Some problems I run into

At some moment I got in maillog : "can't read SMFIC_EOH reply packet header: Success" which was solved after setting the SUBMISSION_DAEMON above as MSA (instead of smtp as I saw somewhere)

Playing with milter_protocol=4 in /etc/postfix/main.cf I got "can't read SMFIC_DATA reply packet header: Success" which was because I've given a value which was not supported. Also milter_protocol=6 thrown error so I let it set on : milter_protocol = 2

Useful commands, part II

  • postconf -d

    Display the default postfix configuration
  • postconf -n

    Display the non-default parameters of the postfix configuration
  • /usr/sbin/sendmail -t -f root@domain.tld myaccount@yahoo.com
    From: root@domain.tld
    Subject: test it
    bla bla
    .

    Test sending email using the sendmail command as defined in the php.ini . Note that php.ini has an additional parameter for sendmail, "-i" which suppress the use of a dot as "end of input" data.
  • ps aux |grep dk

    This should confirm that the filters are running (dk-filter and dkim-filter). It was useful to check this because when I got errors from filters they had just ended silently.

3. Sender-id

This would be the 3rd filter installed and is aimed for hotmail accounts. There is a confusion between Sender-ID and SPF because they both use the same DNS registration record but the implementation of the Sender-ID protocol is similar with DKIM above. Read more about SPF vs Sender ID

Note that in order to sign the emails correctly one would only need the SPF record – see next section. At least this should work for 80% of the emails sent to hotmail/MSN according to the link above.

The init script

I named the init script "/etc/init.d/sender-id" and the command used to start the filter is:

COMMAND="sid-filter -u $USER -t -p inet:$PORT@localhost -l -P $PIDFILE -d $DOMAIN -D -h"

The parameters means:

  • -u username to run under
  • -t test mode (never reject messages)
  • -p socketspecs the socket for postfix to communicate with
  • -l log via syslog (/var/log/maillog)
  • -P the filename which will store the PID of the current process
  • -d a list of domains whose emails should be ignored by this filter.
    Warning : this is a list of the domains to be ignored so if you want to see this filter's signature in the header of your emails then use an empty value for DOMAIN. Somehow strange in my opinion.
  • -D the way to handle the DNS errors (soft failures)
  • -h adds a header indicating the presence of this filter

4. SPF

The SPF authentication is used by google and is quite simple requiring no software installation on the server. In order to generate a SPF record for your domain you will probably have to go to the most-used tool :

Setup wizard to create SPF records for your domain

The record it will create should be placed as a TXT record at your domain and looks like this:

v=spf1 a a:external.domain.tld ~all

Where:

  • "v=spf1" is the SPF protocol version
  • "a" mechanism matching current domain (e.g. my own domain.tld)
  • "a:external.domain.tld" mechanism matching an external domain which may use my own domain.tld to send emails
  • "mx" mechanism matches the current domain's MX records. Useful if I want to have a secondary server act only as mail server
  • "all" mechanism matches everything else. It usually stay at the end. The character which prefixes this mechanism means "SoftFail" and it only indicates that all other domains than the one defined won't be recognizable by this SPF record

Definition: Mechanisms can be used to describe the set of hosts which are designated outbound mailers for the domain.

Observation: the SPF standard specify that there should be used the new DNS registration record type SPF instead of TXT but because of compatibility with the current DNS implementations it is recommended to put both TXT and SPF records with the same content.

Useful commands, part III

Here are some of the tools and commands I used to verify that the record is in place and the configurations above are working:

  • dig domain.tld TXT

    This would query the nameserver for the TXT record and should return something like:
    ;; ANSWER SECTION:
    domain.tld.             300     IN      TXT     "v=spf1 a a:external.domain.tld ~all"
  • Send an email with an empty subject to check-auth@verifier.port25.com . I strongly recommend using an email client because sending from comand prompt resulted sometime in failed Domainkey verification due to probably some extra characters added into the headers. The result will arrive in email and should look like this: Thank you for using the verifier,
    The Port25 Solutions, Inc. team
    ==========================================================
    Summary of Results
    ==========================================================
    SPF check: pass
    DomainKeys check: pass
    DKIM check: pass
    Sender-ID check: pass
    SpamAssassin check: ham
    ==========================================================
  • cd /etc/init.d/; chkconfig --add sender-id

    this adds the script to the list of programs which should run after restart. Do this for each init script

Last thoughts

I invite any reader to help improving this newbie-guide based on their experience and knowledge. There is plenty room for suggestions and additions to this article but this is an area where with all documentation available it seems that it is not enough or not covers all configuration or problems which may occur when setting up such a system. I spent myself several (many) good hours reading and learning, trying and failing or succeeding and finally writing this article hoping that will help others to save some of their time and neurons while trying to follow the latest recommendation of the war against spammers.

Although not required, a donation is always welcome end encouraging ;)

Donation



using PayPal

Resources

Files

DKIM configuration file /etc/dkim.conf

DKIM startup script /etc/init.d/dkim

Domainkeys startup script /etc/init.d/domainkeys

Sender-id startup script /etc/init.d/sender-id

Links

How to Setup DomainKeys Identified Mail (DKIM) with Postfix and Ubuntu Server

http://www.unibia.com/unibianet/systems-networking/how-setup-domainkeys-identified-mail-dkim-postfix-and-ubuntu-server

Setting up DKIM, SPF, Domainkeys DNS, Regular DNS on CentOS 5.3 at Pacificrack.com

http://palma-seo.com/setting-dkim-spf-domainkeys-dns-bind

Set Up DKIM On Postfix With dkim-milter (CentOS 5.2)

http://www.howtoforge.com/set-up-dkim-on-postfix-with-dkim-milter-centos-5.2

DomainKey Implementor's Tools and Library for email servers & clients

http://domainkeys.sourceforge.net/

Set Up DKIM For Multiple Domains On Postfix With dkim-milter 2.8.x (CentOS 5.3)

http://www.howtoforge.com/set-up-dkim-for-multiple-domains-on-postfix-with-dkim-milter-2.8.x-centos-5.3

Setting Up SPF, SenderId, Domain Keys, and DKIM

http://www.digitalsanctuary.com/tech-blog/debian/setting-up-spf-senderid-domain-keys-and-dkim.html

Domain Key / DKIM Key Generation Wizard

http://www.socketlabs.com/services/dkwiz

Domainkeys and DKIM with Postfix – Gentoo Linux wiki

http://en.gentoo-wiki.com/wiki/Domainkeys_and_DKIM_with_Postfix

Postfix Add-on Software

http://www.postfix.org/addon.html

DomainKeys Identified Mail (DKIM) Signatures – RFC

http://www.ietf.org/rfc/rfc4871.txt

Postfix / DKIM

https://help.ubuntu.com/community/Postfix/DKIM

How To Implement SPF In Postfix

http://www.howtoforge.com/postfix_spf

Email authentication guide made by BITS

http://www.bits.org/downloads/Publications%20Page/BITSSenderAuthenticationDeploymentFINALJun09.pdf

Return Path’s Best Practice Guide

http://www.returnpath.net/downloads/resources/Email%20Authentication%20v080107.pdf

Last update: May 5th, 2010


php cache

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »


<pre lang="php">
<?php

$url = "http://www.site.com/file.php";
$dest_file = "footercache.txt"; //be sure it is chmod-ed to 0666 !!

$pagesource = request_cache($url, $dest_file, 3600*24*7);
echo $pagesource;

function request_cache($url, $dest_file, $timeout=7200) {

  if(strlen($dest_file) > 100) $dest_file = substr($dest_file, 20, 60) . substr($dest_file, strlen($dest_file) - 4);//keep some chars and the probable extension

  if(!file_exists($dest_file) || filemtime($dest_file) < (time()-$timeout)) {

    $data = @file_get_contents($url);
    if ($data !== false) {

      $tmpf = tempnam("/tmp","YWS");
      $fp = @fopen($tmpf,"w");
      @fwrite($fp, $data);
      @fclose($fp);
      if(file_exists($dest_file)) @unlink($dest_file);
      rename($tmpf, $dest_file);

    }else{

      touch($dest_file);//update its date only

    }

  } else {

    $data = file_get_contents($dest_file);

  }
  return($data);

}

?>
</pre>


Common PHP functions

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »


<pre lang="php">
<?php
if(version_compare(phpversion(), "5.2.0", "<") && !function_exists("json_encode")){
  include($CFG->root_dir . "/common/json/JSON.php");
  function json_encode($str) {$json = new Services_JSON(); return $json->encode($str);}
  function json_decode($str) {$json = new Services_JSON(); return $json->decode($str);}
}

function parse_input($var_array, $var_name){
  if(!isset($var_array[$var_name])) return "";

  if(!is_array($var_array[$var_name])){
    if (!get_magic_quotes_gpc()) {
      $retVal = trim(addslashes($var_array[$var_name]));
    } else {
      $retVal = trim($var_array[$var_name]);
    }
  }else{
    if (!get_magic_quotes_gpc()) {
      foreach ($var_array[$var_name] as $value){
        $retVal[] = trim(addslashes($value));
      }
    } else {
      foreach ($var_array[$var_name] as $value) {
        $retVal[] = trim($value);
      }
    }
  }
  return $retVal;
}

function dprint($var, $message = ""){
  if(DEBUG){
    echo("DEBUG : $message\r\n");
    if(is_array($var) || is_object($var)){
      print_r($var);
    }else{
      echo($var);
    }
    echo("\r\n");
  }
}

function from_sql_date($sqltime, $date_format="d.m.Y"){
  if("0000-00-00 00:00:00" == $sqltime || "0000-00-00" == $sqltime) return "";

  list($y,$m,$d,$h,$i,$s) = sscanf($sqltime,"%4d-%2d-%2d %2d:%2d:%2d");
  date_default_timezone_set("Etc/GMT+2");
  $time_src = mktime($h, $i, $s, $m, $d, $y);
  return date($date_format, $time_src);
}

function to_sql_date($date){
  list($d,$m,$y) = sscanf($date,"%2d.%2d.%4d");
  $time_src = mktime(0, 0, 0, $m, $d, $y);
  return date("Y-m-d 00:00:00", $time_src);
}
?></pre>


Menu at mouse cursor

Posted: April 16th, 2008 | Author: | Filed under: Developers, Javascript | No Comments »


<pre lang="javascript">
<STYLE TYPE="text/css">
<!--
#dek {POSITION:absolute;VISIBILITY:hidden;Z-INDEX:200;}
//-->
</STYLE>
<DIV ID="dek"></DIV>
<SCRIPT TYPE="text/javascript">
<!--
function popUp(theURL, myWidth, myHeight) {
  var winName = 'feedback';
  var features='toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1';
  //var myWidth = 290;
  //var myHeight = 360;
  var isCenter = 'true';
  if(window.screen)if(isCenter)if(isCenter=="true"){
    var myLeft = (screen.width-myWidth)/2;
    var myTop = (screen.height-myHeight)/2;
    features+=(features!='')?',':'';
    features+=',left='+myLeft+',top='+myTop;
  }
  var handle = window.open(theURL,winName,features+((features!='')?',':'')+'width='+myWidth+',height='+myHeight);
  handle.opener = window;
  handle.focus();
  return handle;
}

Xoffset=0; // modify these values to ...
Yoffset= 0; // change the popup position.
var old,skn,iex=(document.all),yyy=Yoffset;//-1000;
var ns4=document.layers
var ns6=document.getElementById&&!document.all
var ie4=document.all
var must_close = false;
var mouse_x = 0;
var mouse_y = 0;
var timeoutId = false;
function initdek(){
  if (ns4) skn=document.dek;
  else if (ns6) skn=document.getElementById("dek").style;
  else if (ie4) skn=document.all.dek.style;
  
  if(ns4)document.captureEvents(Event.MOUSEMOVE);
  else{
    skn.visibility="visible"
    skn.display="none"
  }
  document.onmousemove=get_mouse;
}
//ONMOUSEOVER="keep_it_open()" ONMOUSEOUT="about_to_close()"
function popupdek(msg){
  keep_it_open();
  var content='<div style="border:1px solid #999; padding:10px;background-color:#f87" ONMOUSEOVER="keep_it_open()" ONMOUSEOUT="about_to_close()">' + msg + '</div>';
  
  yyy=Yoffset;
  skn.left = mouse_x;
  skn.top = mouse_y;
  if(ns4){skn.document.write(content);skn.document.close();skn.visibility="visible"}
  if(ns6){document.getElementById("dek").innerHTML=content;skn.display=''}
  if(ie4){document.all("dek").innerHTML=content;skn.display=''}
}

function get_mouse(e){
  if(ns4||ns6){
    mouse_x=e.pageX+Xoffset+'px';
    mouse_y=e.pageY+yyy + 'px';
  }else{
    if (document.documentElement){
      // IE6 +4.01
      mouse_x=event.x+document.documentElement.scrollLeft+Xoffset+'px';
      mouse_y=event.y+document.documentElement.scrollTop+yyy + 'px';
    }else if (document.body){
      // IE5 or DTD 3.2
      mouse_x=event.x+document.body.scrollLeft+Xoffset+'px';
      mouse_y=event.y+document.body.scrollTop+yyy + 'px';
    }
  }
}

function kill(){
//yyy=-1000;
if(ns4){skn.visibility="hidden";}
else if (ns6||ie4)
  skn.display="none"
  is_visible=0;
}

function keep_it_open(){
  if(timeoutId) clearTimeout(timeoutId);
  timeoutId = false;
}

function about_to_close(){
  timeoutId = setTimeout('kill()',1000);
}

function set_must_close(){
  must_close=true;
  kill();
}

initdek();

function showTags(str){
  var msg = "<strong>Tags:</strong><br/>" + str.replace(/\,/,'<br/>');
  msg += '<br/><form action=""><input type="text" size="10" value="enter tag.." name="tag"/><input type="submit" value="Add"></form>';
  popupdek(msg);
}
function showManage(pid){
  var msg = "<strong>Management:</strong><br/>" ;
  msg += '<a href="#" onclick="popUp(\'imageop/add_image~' + pid + '.html\',400,300)" >Add image</a><br/>';
  msg += '<a href="#" onclick="popUp(\'imageop/delete_image~' + pid + '.html\',400,300)" >Delete image</a><br/>';
  msg += '<br/><form action=""><input type="file" size="10" value="" name="uploadfile"/><br/><input type="submit" value="Upload"></form>';
  popupdek(msg);
}

function showLinks(pid, iurl){
  var msg = "<strong>Links:</strong><br/>" ;
  msg += '<a href="<?=$PROFILEORIGIN?>/list_profile~' + pid + '.html" target="_blank">Profile home</a><br/>';
  msg += '<a href="' + iurl + '" target="_blank" >Source URL</a><br/>';
  popupdek(msg);
}
//-->
</SCRIPT>
</pre>

Used as:
<a href="http://www.blogger.com/post-edit.do#" onmouseover="showTags('taglist,comma separated)');keep_it_open()" onmouseout="about_to_close()" onclick="return false">Tags</a>


RegEx email parser

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »

Split email formats in pieces through preg_match:

$str=' (|(([^a-zA-Z0-9_\-.]|)(.*?)(|[^a-zA-Z0-9_\-.]+?)([a-zA-Z0-9_\-.]+?)(|[^a-zA-Z0-9_\-.]+?)))(|[^a-zA-Z0-9_\-.])([a-zA-Z0-9_\-.]+?)(|[^a-zA-Z0-9_\-.])@(.+?)\.([^>]+)';


Format long texts

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »


<pre lang="php">
<?php
/**
 * Cut a text so it won't have more than $max_length chars and any word should not have more than $max_word chars
 *
 * @param int $length_limit
 * @param int $length_word
 */
function format_long_text($str, $max_length=99999, $max_word = 60){
  //limit string length
  $has_tail = false;
  if(strlen($str) > $max_length){
    $new_str = substr($str, 0, $max_length);
    //search for non-alpha char
    for($i = $max_length; $i < strlen($str) && ctype_alpha($str[$i]); $i++) $new_str .= $str[$i];
    $str = $new_str;
    $has_tail = true;
  }

  if(3 < $max_word && $max_word < $max_length){
    do{
      //$stripped_str = strip_tags($str);
      //$words = explode(' ', $stripped_str);
      $words = explode(' ', $str);
      $do_loop = false;
      foreach ($words as $word){

        if(strlen($word) > $max_word){
          //bug in IE: point followed by char does not split the text
          $fixed_word = str_replace('.', '. ', $word);

          $new_word = '';
          $j = 0;
          for($i = 0; $i < strlen($fixed_word); $i++){
            $j = (' ' == $fixed_word[$i]?0:$j+1);

            if(($j+1)%$max_word==0){
              $new_word .= ' ' . $fixed_word[$i];
            }else{
              $new_word .= $fixed_word[$i];
            }
          }
          $str = str_replace($word, $new_word, $str);
          $do_loop = true;
          break;
        }
      }
    }while($do_loop);
  }

  return $str . ($has_tail?'..':'');
}
?>
</pre>


Phrase to URL-format

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »

preg_replace('/[^a-zA-Z]+/','_',$phrase)


Instant popup on mouseover

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »


<pre lang="javascript">
<style type="text/css">
<!--
#dek {POSITION:absolute;VISIBILITY:hidden;Z-INDEX:200;}
//-->
</style>

<script type="text/javascript">
<!--
Xoffset=0; // modify these values to ...Yoffset= 20; // change the popup position.
var old,skn,iex=(document.all),yyy=-1000;
var ns4=document.layersvar ns6=document.getElementById&#038;&#038;!document.allvar ie4=document.all

if (ns4)skn=document.dek
else if (ns6)skn=document.getElementById("dek").style
else if (ie4)skn=document.all.dek.style
if(ns4)document.captureEvents(Event.MOUSEMOVE);
else{skn.visibility="visible"skn.display="none"}
document.onmousemove=get_mouse;

function popup(msg,bak){
  var content="
<table>
<tr>
<td";</td>
content += " bgcolor=\'"+bak+"\'";

  content += ">"+msg+"</td>
</tr>
</table>
";

  yyy=Yoffset;
  if(ns4){
    skn.document.write(content);
    skn.document.close();
    skn.visibility="visible"
  }
  if(ns6){
    document.getElementById("dek").innerHTML=content;
    skn.display=\'\'
  }
  if(ie4){
    document.all("dek").innerHTML=content;
    skn.display=\'\'
  }
}

function get_mouse(e){
  if(ns4||ns6){
    skn.left=e.pageX+Xoffset+\'px\';
    skn.top=e.pageY+yyy + \'px\';
  }else{
    if (document.documentElement){ // IE6 +4.01
      skn.left=event.x+document.documentElement.scrollLeft+Xoffset+\'px\';
      skn.top=event.y+document.documentElement.scrollTop+yyy + \'px\';
    }else if (document.body){ // IE5 or DTD 3.2
      skn.left=event.x+document.body.scrollLeft+Xoffset+\'px\';
      skn.top=event.y+document.body.scrollTop+yyy + \'px\';
    }
  }
}

function kill(){
  yyy=-1000;
  if(ns4){
    skn.visibility="hidden";
  }else if (ns6||ie4)skn.display="none"
}
//--></script></pre>

Usage: <a href="mylinkhere.php" onmouseover="popup('this is a help message', '#00FFFF')" onmouseout="kill()" >click here</a>


META tag library

Posted: April 16th, 2008 | Author: | Filed under: Developers | No Comments »

This library if for obtaining content for the META TAGS like keywords, description and also for computing tags to be used in searches based on the given text.

Metatag generator library (metataggen_library.zip)