Skip to content
Dez 28 09

PHP: Array rekursiv durchlaufen

by dennis

Um zum Beispiel die Funktion htmlentities auf ein Array rekursiv anzuwenden kann man wie folgt vorgehen:

1. Eine neue (rekursive) Funktion arr_htmlentities erstellen:

        function arr_htmlentities($arr) {
                foreach ($arr as $key=>$value) {
                        if (!is_array($arr[$key])) {
                                $arr[$key] = htmlentities($arr[$key]);
                        } else {
                                $arr[$key] = arr_htmlentities($arr[$key]);
                        }
                }
                return $arr;
        }

2. Die neue Funktion für das array $_POST (z.B. Eingaben aus einem Kontaktformular) aufrufen:

$userInput = arr_htmlentities($_POST);
 
// ausgabe:
print_r($userInput);
Dez 12 09

PHP: Differenz zwischen 2 Timestamps berechnen

by dennis

Lange gesucht und am Ende hier gefunden:

http://de2.php.net/manual/de/function.date-diff.php#93915

Die Funktion berechnet die Differenz zwischen 2 Timestamps und gibt als Rückgabewert ein Array mit den Jahren, Monaten, Tagen, Stunden, Minuten und Sekunden:

function date_diff($d1, $d2){
/* This is correctly working time differentiating function. It's resistant to problems with 
   leap year and different days of month. Inputs are two timestamps and function returns array 
   with differences in year, month, day, hour, minute a nd second.
 
   Compares two timestamps and returns array with differencies (year, month, day, hour, minute, second)
 
   More infos at http://de2.php.net/manual/de/function.date-diff.php#93915
*/
        //check higher timestamp and switch if neccessary
        if ($d1 < $d2) {
                $temp = $d2;
                $d2 = $d1;
                $d1 = $temp;
        } else {
                $temp = $d1; //temp can be used for day count if required
        }
        $d1 = date_parse(date("Y-m-d H:i:s",$d1));
        $d2 = date_parse(date("Y-m-d H:i:s",$d2));
        //seconds
        if ($d1['second'] >= $d2['second']){
                $diff['second'] = $d1['second'] - $d2['second'];
        } else {
                $d1['minute']--;
                $diff['second'] = 60-$d2['second']+$d1['second'];
        }
        //minutes
        if ($d1['minute'] >= $d2['minute']){
                $diff['minute'] = $d1['minute'] - $d2['minute'];
        } else {
                $d1['hour']--;
                $diff['minute'] = 60-$d2['minute']+$d1['minute'];
        }
        //hours
        if ($d1['hour'] >= $d2['hour']){
                $diff['hour'] = $d1['hour'] - $d2['hour'];
        } else {
                $d1['day']--;
                $diff['hour'] = 24-$d2['hour']+$d1['hour'];
        }
        //days
        if ($d1['day'] >= $d2['day']){
                $diff['day'] = $d1['day'] - $d2['day'];
        } else {
                $d1['month']--;
                $diff['day'] = date("t",$temp)-$d2['day']+$d1['day'];
        }
        //months
        if ($d1['month'] >= $d2['month']){
                $diff['month'] = $d1['month'] - $d2['month'];
        } else {
                $d1['year']--;
                $diff['month'] = 12-$d2['month']+$d1['month'];
        }
        //years
        $diff['year'] = $d1['year'] - $d2['year'];
        return $diff;   
}

Hier mal ein paar kleine Berechnungen zu Geburtsdaten:

define(BIRTHDAY, strtotime('1980-08-26 15:25:00')); // geburtsdatum
$now  = time(); // aktuelles datum
 
// geburtsdatum dieses jahr:
$birthdayThisYear = mktime(date('H',BIRTHDAY),date('i',BIRTHDAY),date('s',BIRTHDAY),date('n',BIRTHDAY),date('j',BIRTHDAY),date('Y',$now));
 
// geburtsdatum nächstes jahr:
$birthdayNextYear = mktime(date('H',BIRTHDAY),date('i',BIRTHDAY),date('s',BIRTHDAY),date('n',BIRTHDAY),date('j',BIRTHDAY),date('Y',$now)+1);
 
// geburtsdatum letztes jahr:
$birthdayLastYear = mktime(date('H',BIRTHDAY),date('i',BIRTHDAY),date('s',BIRTHDAY),date('n',BIRTHDAY),date('j',BIRTHDAY),date('Y',$now)-1);                                                                                                                              
 
// der nächste geburtstag:
$nextBirthday     = ($now<$birthdayThisYear)?$birthdayThisYear:$birthdayNextYear;                           
 
// der letzte geburtstag:
$lastBirthday     = ($now<=$birthdayThisYear)?$birthdayLastYear:$birthdayThisYear;
 
// wie viel prozent des jahres bis zum nächsten geburtstag sind schon um? 
$percent          = ($now-$lastBirthday) / ($nextBirthday-$lastBirthday) * 100;
 
// wie viele tage sind es noch bis zum nächsten geburtstag?
$days2Birthday    = floor(($nextBirthday - $now) / 86400);
 
// alter als array  (jahre, monate, tage, stunden, minuten, sekunden - schaltjahre werde berücksichtigt!)
$age              = date_diff(BIRTHDAY, $now);
Dez 10 09

Passwörter mit PHP generieren

by dennis

Ein paar Funktionen um ein Passwort mit PHP zu generieren:

1. Mnemonisch (Konsonant-Vokal-Konsonant-Vokal…)

function mnemonicWord($length) {
        // mnemonicWord - www.quirks-modus.de
        $konsonanten = array ('b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z');
        $vokale = array('a','e','i','o','u');
        $pw="";
        for ($i=1; $i<=$length; $i++) {
                $pw.=($i%2!=0)?$konsonanten[rand(0, count($konsonanten)-1)]:$vokale[rand(0, count($vokale)-1)];
        }
        return $pw;
};

Beipielausgabe: loxatituta

2. Buchstaben und Zahlen

function wordWithNumbers($length) {
        // wordWithNumbers - www.quirks-modus.de
        $data = array();
        array_push($data,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z');
        array_push($data,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
        array_push($data,'0','1','2','3','4','5','6','7','8','9');
        $pw = "";
        for ($i=1; $i<=$length; $i++) {
                $pw.= $data[rand(0,count($data)-1)];
        }
        return $pw;
}

Beipielausgabe: xwEWFuMeg7

3. “Sicher”

function passwdGen($length) {
        // passwdGen - www.quirks-modus.de
        $pw="";
        for ($i=1; $i<=$length; $i++) {
                $char = rand(33,122);
                if ($char == 39 ) $char = 52;
                if ($char == 44 ) $char = 54;
                if ($char == 94 ) $char = 56;
                if ($char == 96 ) $char = 48;
                $pw.= chr($char);
        }
        return $pw;
}

Beipielausgabe: kIA8I:W/=9

4. to leet

function t1337($word) {
        // t1337 (to leet) - www.quirks-modus.de
        $leets = array(
                'A' => '4',  'B' => '8',  'C' => '(',    'D' => '|)',  'E' => '3',
                'F' => 'PH', 'G' => '6',  'H' => '/-/',  'I' => '!',   'J' => '_|',
                'K' => '|<', 'L' => '[_', 'M' => '/v\\', 'N' => '/\/', 'O' => '0',
                'P' => 'p',  'Q' => '0_', 'R' => '|2',   'S' => '5',   'T' => '7',
                'U' => 'v',  'V' => 'V',  'W' => '\/\/', 'X' => '%',   'Y' => '°/',
                'Z' => 'z');
        $ret = '';
        for($i=0; $i<strlen($word); $i++) {
                $ret.=$leets[strtoupper($word[$i])];
        }
        return $ret;
}

Beipielausgabe für t1337(‘Dennis’): |)3/\//\/!5

Dez 2 09

jQuery inlineEdit

by dennis

Ein kleines jQuery Plugin, welches onClick auf einen DIV oder SPAN den Inhalt in eine Textarea umwandelt und den geänderten Text per AJAX POST Request an eine PHP Datei (oder ähnlich) schickt.

Beipiel hier: www.quirks-modus.de/_inlineEdit/

jquery.inlineEdit.js:

/*
 * jquery.inlineEdit.js - jQuery Plugin
 * Simple and easy to use inline editor
 *
 * Author: Dennis Lehmann
 * Examples and documentation at: www.quirks-modus.de/_inlineEdit/
 * 
 * Version: 1.1 (01/04/2010)
 * Requires: jQuery v1.3+
 * 
 * Licensed under the GPL license:
 *   http://www.gnu.org/licenses/gpl.html
 */
 
jQuery.inlineEdit = function(actual, options) {
        var changing = false;
        function fieldBlur(content,old_content,elem) {
                if (content!="") {
                      	postData = options.postData || {};
                        postData = $.extend({
                                'content' : content
                        }, options.postData);
                        // post postData and get new content from options.requestURL    
                        $(elem).load(options.requestUrl,postData,function(){
                                if ($(this).html()=='false') {
                                        $(this).html(old_content);
                                        options.onError();
                                } else {
                                        options.onSuccess();
                                }
                        });
                } else {
                        // write old content into the textarea
                        $(elem).html(old_content);
                } 
                changing = false;
                return false;
        }
 
        $(actual).click(function(){
                if(!changing){
                        old_content = $(actual).html();
                        width  = ($(actual).width() < options.minWidth)?options.minWidth:$(actual).width()+5;
 
                        var textarea = document.createElement('textarea');
                        $(textarea).attr({ name  : 'textarea'});
                        $(textarea).css({
                                'width'  : width+'px', 
                                'height' : $(actual).height()+'px',
                        });
                        $(textarea).focus(function(){$(this).css({'border':options.borderStyle});});
                        $(textarea).blur(function(){
                                $(this).css({'border':'0'});    
                                return fieldBlur($(this).val(),old_content,$(actual));
                        });
                        $(textarea).keydown(function(){
                                if ($(this).scrollTop()>0) { 
                                        $(this).css({'height':($(this).height()+$(this).scrollTop())});
                                }
                        });
                        $(textarea).html($(actual).html().replace(/<br\s*\/?>/img,""));
                        $(actual).html(textarea);
                        $(textarea).focus();      
                        changing = true;
                }
        });
}
 
jQuery.fn.inlineEdit = function(options) {
        options = options || {};
        // set default values for required options
        options = $.extend({
                requestUrl  : "inlineEditUpdate.php",
                minWidth    : null,
                borderStyle : '1px dashed #dadada',
                onError     : function() {
                        // starts if the request-script returns the string "false"
                        alert('An error occurred.');
                },
                onSuccess   : function() {
                        // starts if the request-script returns NOT the string "false" 
                }
        }, options);        
        this.each(function(){
                new jQuery.inlineEdit(this,options);
        });
        return this;        
};

Die Verarbeitung mit PHP erfolgt dann z.B. so:

<?
        /* der parameter $_POST['content'] enthält den eingegebenen Text.
         * in diesem beipiel wird die gepostete eingabe einfach wieder 
         * ausgegeben:
        */         
        $cnt = trim(stripslashes(strip_tags(str_replace("'","’",$_POST['content']))));
        echo $cnt;
 
 
?>

Der Aufruf für ein Element (DIV oder SPAN) mit der Klasse .test:

$('.test').inlineEdit();

Aufruf mit verschiedenen Optionen:

$('.test').inlineEdit({
        requestUrl  : '/libs/php/update.php',
        minWidth    : 10,
        borderStyle : '1px dashed #dadada',
        postData    : {
                'title' : $(this).attr('title') 
        }
});

Mögliche Parameter:

requestUrl (String) hier wird der AJAX Request per POST hingeschickt.
minWidth (Integer) mindestbreite von Eingabefeldern (bei inline-Elementen)
borderStyle (String) CSS-Eigenschaft border für das Eingabefeld
postData (JSON) Daten die per POST verschickt werden. $_POST['content'] enthält den eingegebenen Text.

Viel Spaß damit!

Nov 26 09

Input – Feld “deluxe”

by axel

Vorhaben: Kontakformular !
Das label und dadrunter oder auch daneben die input-Felder… ist die gängige Lösung, aber schön und “innovativ” ist das nicht. Ein bißchen edler wird es folgendermaßen.

Ohne css sieht so aus,wegen der Validität bleiben die labels drin, können aber auch einfach weggelassen werden:

html:

1
2
<label>Name:</label>
                <input type="text" name="Name" value="Name" onfocus="if(this.value=='Name'){this.value='';}" onblur="if(this.value==''){this.value='Name';}" /><br />

Per css noch die label’s rausschieben.

css:

1
2
3
4
5
6
7
8
9
10
11
12
13
label {
display:block;
text-indent: -3000px;
float:left;
}
 
input{
width:180px;
font: 12px georgia, "Times New Roman", Times, serif;
color:#000;
float:left;
margin-bottom: 3px;
}
Nov 23 09

Geldbeträge formatieren mit Smarty (money-format plugin)

by dennis

Einfach folgendes Script mit dem Namen modifier.money_format.php in den Ordner “/libs/plugins/” von Smarty kopieren:

<?php
/**
 * Smarty plugin
 * @package Smarty
 * @subpackage plugins
 */
 
/**
 * Smarty money_format modifier plugin
 *
 * Type:     modifier<br>
 * Name:     money_format<br>
 * Purpose:  Formats a number as a html-encoded currency string
 * @link http://www.php.net/money_format
 * @param float
 * @param integer (default 0)
 * @return string (html-encoded)
 */
function smarty_modifier_money_format($number, $leftFill='0') {
        setlocale(LC_MONETARY, 'de_DE');
        $format = (!empty($leftFill))?'%!#'.$leftFill.'n':'%!n';
        return str_replace(' ','&nbsp;',money_format($format, $number));
}
 
?>

Template Variable $preis formatiert ausgeben:

{$preis|money_format}    {* "deutsch" formatiert *}
{$preis|money_format:5} {* "deutsch" formatiert, vorkommastellen mit führenden leerzeichen (&nbsp;) auf 5 aufgefüllt *}
Nov 17 09

Footer immer am unteren Browser-Rand

by axel

Kleines Problem:
Der Footer soll immer unten am Rand des Browsers zusehen sein, egal wie lang der Content ist. Mit position:absolute;bottom:0; ist der Footer schon da wo er hin soll. ABER! wenn mein Content so lang ist das ein Scrollbalken entsteht, und ich dann scrolle, scrollt der Footer mit dem Content hoch :-(.

Lösung:
der Body soll nicht scrollen, dafür aber der div “page”. Siehe html/css unten.

Nur mit Position:

Mit Position und page-overflow:auto;:

html/css:

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
<html>
  <head>
      <title>Footer immer am unteren Browser-Rand</title>
      <style type="text/css" media="all">
            *{margin:0;padding:0;border:0;}
            * html body{overflow:hidden;}          
            #footer{position:absolute;bottom:0;width:100%;background-color: #f00;}
            #page{height:100%;overflow:auto;}
            #content{width:300px;}
      </style>
  </head>
      <body>
            <div id="footer"> 
                  FOOTER-BEREICH 
            </div>
            <div id="page">
                  <div id="content">
                        CONTENT<br /> 
                        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget 
                        dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, 
                        nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. 
                  </div>
            </div>
      </body>
</html>

Wer den unteren Pfeil vom Scrollbalken sehen will, gibt halt nicht width:100%; an.

Funktioniert im: ie5.5-8, ff3, opera, safari…

Nov 16 09

Eierlegende Wollmilchsau – für Flash

by axel

schieben – drehen – skalieren & Deckkraft ändern mit einer Funktion in Flash – AS

Hier ein prototype mit dem ich schon viel Spaß hatte ;-)
Wenn einer sagt das geht in as2 oder as3 einfacher und schneller… her mit dem as.

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
MovieClip.prototype.moveXYRSA = function(xValue, yValue, rValue, sValue, aValue) {
	this.onEnterFrame = function() {
		var v7 = aValue-this._alpha;
		this._alpha += v7*0.125;
		var v6 = sValue-this._xscale;
		this._xscale += v6*0.15;
		var v5 = sValue-this._yscale;
		this._yscale += v5*0.15;
		var v4 = rValue-this._rotation;
		this._rotation += v4*0.15;
		var v3 = xValue-this._x;
		this._x += v3*0.15;
		var v2 = yValue-this._y;
		this._y += v2*0.15;
 
		if (Math.abs(v2)<0.15 && Math.abs(v3)<0.3 && Math.abs(v4)<0.15 && Math.abs(v5)<0.15  
			&& Math.abs(v7)<1.18){
			this.onEnterFrame = null;
			trace("STOP");
		}
	};
};
 
//NAVIGATIONSPUNKTE
_root.frisuren_btn.onRelease = function() {
	inhalt_mc.moveXYRSA(-1800, 0, 0, 100, 100);
	act_mc.moveXYRSA(430, 462, 0, 100, 100);
	_root.hide_frisuren_mc.moveXYRSA(388.4, 490.2, 0, 100, 0);
	_root.hide_service_mc.moveXYRSA(483.6, 470.2, 0, 100, 100);
	_root.hide_nagelpflege_mc.moveXYRSA(578, 503.1, 0, 100, 100);
	_root.hide_fusspflege_mc.moveXYRSA(578, 483.1, 0, 100, 100);
};
Okt 7 09

HTML-Text mit Hintergrundfarbe

by axel

Mengentext der auf unruhigem Hindergrund gesetzt ist, ist höchst wahrscheinlich nicht sehr lesefreundlich. Abhilfe schafft folgender Schnipsel, der dem Text einen einfarbigen Hintergrund/Balken gibt, und zwar nur dem Text und nicht der ganzen Zeile.

Vorschau:

html:

1
2
3
4
5
6
7
<div style="width:240px;">
      <p>
            <span>
                  Mengentext der auf unruhigem Hindergrund gesetzt ist, ist höchst wahrscheinlich nicht sehr lesefreundlich.
            </span>
      </p>
</div>

css:

1
2
3
4
5
6
7
8
p span {
      -moz-background-clip:border;
      -moz-background-inline-policy:continuous;
      -moz-background-origin:padding;
      background:#FFFFFF none repeat scroll 0 0;
      color:#000000;
      line-height:22px;
}

Das ganze funktioniert im IE 5.5 6 7 8 FF Opera und Safari !

Sep 10 09

xt:commerce: Kategorien als verschachtelte Liste darstellen

by dennis

Hier eine angepasste Version der Datei xtc_show_category.inc.php, die eine korrekt ineinander verschachtelte Liste von Kategorien und Unterkategorien erzeugt. Das Original gibt’s hier:

http://www.blogpotato.de/2006/11/16/xtc-und-semantisch-korrekter-code/

/*
    -----------------------------------------------------------------------------------------
    $Id: xtc_show_category.inc.php 1262 2005-09-30 10:00:32Z mz $
 
    XT-Commerce - community made shopping
    http://www.xt-commerce.com
 
    Copyright (c) 2003 XT-Commerce
    -----------------------------------------------------------------------------------------
    based on:
    (c) 2000-2001 The Exchange Project  (earlier name of osCommerce)
    (c) 2002-2003 osCommerce(categories.php,v 1.23 2002/11/12); www.oscommerce.com
    (c) 2003     nextcommerce (xtc_show_category.inc.php,v 1.4 2003/08/13); www.nextcommerce.org
 
    Released under the GNU General Public License
    -----------------------------------------------------------------------------------------
    Modified to get a cleaner HTML-output without tables
    Bugfix
    Shows, which categories have subcategories
    by Gunnar Tillmann
    http://www.gunnart.de
    -----------------------------------------------------------------------------------------
    Modified to get neatly nested unordered lists instead of marking sublevels with classes
    by Matt Slovig
    http://www.wibros.de
    -----------------------------------------------------------------------------------------
*/
 
function xtc_show_category($counter) {
        global $foo, $categories_string, $id, $current_level;
 
        for ($a=0; $a<$foo[$counter]['level']; $a++) {}
 
        if(empty($categories_string)) {
                $categories_string = "<ul>";    
        }
 
        $cPath_new = xtc_category_link($counter,$foo[$counter]['name']);
        if (SHOW_COUNTS == 'true') {
                    $products_in_category = xtc_count_products_in_category($counter);
        }
        if ($foo[$counter]['next_id']) { // There's another entry coming        
                if($foo[$foo[$counter]["next_id"]]["level"]>$foo[$counter]["level"]) { // next entry is one level below the current (ie submenu to current entry)
                        $ul = "<ul>";    // open a new list
                }
                if($foo[$foo[$counter]["next_id"]]["level"]<$foo[$counter]["level"]) { // next entry is at least one level above the current (ie current submenu ends here)
                        $ul = "</li>"; // close current entry
                        for($x=$foo[$counter]["level"];$x>$foo[$foo[$counter]["next_id"]]["level"];$x--) {
                               $ul .= "</ul></li>\r\n";    // close all remaining lists. As it is possible to jump from a deep level directly to root level, we have to do this by iterating from current level to next level
                        }
                }
                if($foo[$foo[$counter]["next_id"]]["level"]==$foo[$counter]["level"]) { // next entry is on the same level
                    $ul = "</li>\r\n"; // jut close the list entry
                }
        }
 
        $categories_string .= sprintf("\r\n<li class='%s %s'><a href='%s' class='%s'>%s</a>%s%s", $foo[$counter]['level']=='' ? "main" : "sub", xtc_has_category_subcategories($counter)==true ? "submenu" : "normal", xtc_href_link(FILENAME_DEFAULT, $cPath_new), isset($id) && is_array($id) && in_array($counter, $id) ? "active" : "normal", $foo[$counter]['name'], isset($products_in_category) && $products_in_category>0 ? sprintf(' <span class="catcount">(%s)</span>', $products_in_category) : "", $ul); // building it together
 
        $current_level = $foo[$counter]["level"]; // set current level, so we can iterate downwards when we are done
        if ($foo[$counter]['next_id']) {
                xtc_show_category($foo[$counter]['next_id']);
        } else {
                // close remaining </ul>'s, iterating down from $current_level to 0        
                for($x=$current_level;$x>0;$x--) {
                       $categories_string .= '</li></ul>';
                }
                $categories_string .= '</li></ul>'; // Close the entire list
        }
}

Erzeugt folgende Ausgabe:

<ul>
   <li><a href="#">Kategorie I</a>
    <ul>
         <li><a href="#">Unterkategorie I</a></li>
         <li><a href="#">Unterkategorie II</a></li>
      </ul>
   </li>
   <li><a href="#">Kategorie II</a></li>
</ul>