by:

Hallo,

nachdem mir heute etwas langweilig war und ich alles machen wollte, nur nicht das was ich sollte, hier ein kleiner Script der eine Shoutbox erzeugt.

Das Besondere ist, er kommt ohne Datenbank aus und benutzt ajax damit neu hinzugefügte Inhalte gleich angezeigt werden. Man kann ihn also auch als simplen Chatscript benutzen. Noch nicht implementiert sind Smilies, sollte sich aber mit str_replace recht einfach umsetzen lassen.

Source Code Downloaden | Demo

Code

<?php
# Shoutbox 1.0
# by Andreas Beder
# codejungle.org
# Licence GNU GPL 2

//config

$filename="content.txt";
// be sure the file have write permissions
$url="http://www.codejungle.org/shoutbox/";

//function 

function get_content(){
global 
$filename;
      
$lines file ($filename);
      
$start count($lines)-12;
      if (
$start 1$start 1;
      for (
$i $start$i count ($lines); $i++){
      
$somecontent.=stripslashes($lines[$i]);
      }
return 
$somecontent;
}

function 
add_content(){
global 
$filename;
if(
$_POST[submit] and $_POST[nick] and $_POST[content]){
//check content
//add content
 
$_SESSION["nick"]=$_POST[nick];
 
$somecontent=strip_tags($_POST[nick]).": ".strip_tags($_POST[content])."<br/>n";
 
$handle fopen($filename'a+');
 
fwrite($handle$somecontent);
}
}

function 
output_form(){

echo 
'
<form action="" method="post">
Nick:'
;
if(
$_SESSION[nick]){echo $_SESSION[nick].'<input type="hidden" name="nick" value="'.$_SESSION[nick].'"><br>';} else { echo '<br>
<input name="nick" type="text" value="'
.$_SESSION[nick].'"><br>'; }
echo
'
Text:<br>
<textarea rows="5" cols="100" name="content"></textarea><br>
<input type="submit" name="submit" value="save">
</form>
'
;

}

if(
$_GET[content]=="true"){
echo 
get_content();
die();
}
?>
<html>
<head>
<title>shoutbox demo</title>
<script type="text/javascript" language="javascript">

    var http_request = false;

    function macheRequest(url) {

        http_request = false;

        if (window.XMLHttpRequest) { // Mozilla, Safari,...
            http_request = new XMLHttpRequest();
            if (http_request.overrideMimeType) {
                http_request.overrideMimeType('text/xml');
                // zu dieser Zeile siehe weiter unten
            }
        } else if (window.ActiveXObject) { // IE
            try {
                http_request = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    http_request = new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e) {}
            }
        }

        if (!http_request) {
            alert('Ende :( Kann keine XMLHTTP-Instanz erzeugen');
            return false;
        }
        http_request.onreadystatechange = alertInhalt;
        http_request.open('GET', url, true);
        http_request.send(null);

    }

    function alertInhalt() {

        if (http_request.readyState == 4) {
            if (http_request.status == 200) {
                document.getElementById("shoutbox").innerHTML=http_request.responseText;
                var objDiv = document.getElementById("shoutbox");
                objDiv.scrollTop = objDiv.scrollHeight;
                setTimeout('macheRequest("<?php echo $url?>?content=true")',2000);

            } else {
                alert('Bei dem Request ist ein Problem aufgetreten.');
            }
        }

    }
</script>
</head>
<body onload="macheRequest('<?php echo $url?>?content=true');">
<? add_content(); ?>
<div style="border:1px solid #ccc; width:500px; height:300px; max-height:300px; overflow:auto;"
 name="shoutbox" id="shoutbox">
</div>
<? output_form(); ?>

</body>
</html>

Beachte, dass die content.txt Schreibrechte für den Webserver haben sollte.

Unter *nix geht das folgendermaßen:

chmod 640 content.txt && chown nobody:nogroup content.txt

Ich hoffe euch hat mein Script gefallen, über Verbesserungsvorschläge freue ich mich natürlich auch.

LG

Andreas


Kommentare

by:

1. PHP caching mit eaccelerator
2. MySQL und Indexes
3. MySQL socket over TCP
4. PHP Sessionhandler DB
5. Temp- Dateien von MySQL und PHP
6. Codeprofiling
7. MySQL- Proxy
8. Benchmarking


1. Caching mit eaccelerator

eaccelerator ist eine gute Wahl für Server, die eine hohe Last bewältigen müssen.
Die Vorteile liegen darin, dass PHP Skripte nicht bei jedem Aufruf neu gelesen und
interpretiert werden müssen, was bei mehreren Anfragen Zeit spart.
Ausserdem schont es die Festplatte, da der interpretierte Code im RAM gehalten wird.
Es gibt diverse Benchmarks die belegen sollten, dass eaccelerator eines der besten Cachingsysteme für PHP ist.
Ich selber verwende eaccelerator seit mehreren Jahren und bin sehr zufrieden.

2. MySQL und Indexes

Etwas worauf man immer wieder stößt, wenn man sich mit Performance und MySQL beschäftigt, ist die Aufforderung Indexe richtig zu setzen. Dem kann man eigentlich wenig hinzufügen.
Es hat sich gezeigt, dass gerade bei größeren DBs die Geschwindigkeit dramatisch gesteigert werden kann, wenn man seine Indexes richtig setzt.
Die MySQL Funktion "explain" hilft dabei queries zu optimieren.

3. MySql und Sockets

Wenn es möglich ist, sollte man Socket- Verbindungen der TCP- Verbindung vorziehen, da TCP- Verbindungen meist nur ein unnötiger Overhead sind. Manche Seiten berichten von einem Performancegewinn bis zu 20 %.
Die Verbindung lässt sich in PHP relativ einfach aufbauen,
entweder man verwendet beim mysql_connect localhost, dann versucht die Funktion
selbstständig eine Socket- Verbindung aufzubauen, oder man gibt den Pfad direkt an:

Code

<?php mysql_connect("/tmp/mysql.sock""root""pass"); ?>


4. PHP Sessionhandler

Ich verwende seit kurzem für mein CMS einen Datenbank- Sessionhandler, weniger aus Performance- Gründen, als mehr zur Lastverteilung.
Wie ein Datenbank- Sessionhandler ausschaut, könnt ihr euch hier ansehen:
http://www.codejungle.org/tag/Database_Session_handler_for_php/3.html

5. Temp- Dateien von MySQL und PHP

Temporäre Dateien von MySQL und PHP kann man auch im RAM speichern,
dazu legt man einfach ein Verzeichnis im tmp Ordner an:
mkdir /tmp/ram
und weist einen Teil des Arbeitsspeichers diesem Verzeichnis zu (in dem Fall 150mb):
/bin/mount -t tmpfs /dev/shm /tmp/ram/ -o size=150m

Danach muss man MySQL und PHP nur noch sagen wo sie die Temp Dateien speichern sollen.

MySQL mit dem Parameter --tempdir=/tmp/ram/ starten
und in der php.ini den session.save_path auf /tmp/ram/ setzen.

Nach meinen Tests hat dies zwar nicht viel Performance gebracht, aber naja, Kleinvieh macht auch Mist.

6. Code Profiling

Code Profiling ist eine nützliche Methode um seinen Code zu verbessern.
Man sieht, welche Funktionen wie viel Speicher, CPU und Zeit brauchen und kann
dann seinen Code optimieren. Ich selber habe xdebug zum optimieren verwendet,
es gibt aber auch noch eine Reihe anderer Profiler.
mod-top z.B. habe ich mir bisher zwar noch nicht näher angeschaut, es scheint aber auch relativ brauchbar zu sein.

7. MySQL- Proxy

MySQL- Proxy kann man als DB Lastenverteiler, aber auch als eine Failover Lösung benutzen.
Ich selber habe einige Lastenverteiler getestet und hier meine Ergebnisse veröffentlicht:

http://www.codejungle.org/tag/Lastenverteilung_mit_MySQL_und_SQLrelay/5.html


8. Benchmarking

Bevor man in den produktiven Betrieb geht sollte man seine Anwendung immer einem Benchmark unterziehen.
Eine einfache Methode ist AB, was für Apache Benchmark steht.
Mit AB ist es möglich mehrere Anfragen paralell an den Webserver zu senden und in den meisten Fällen kann man so auch die Grenzen des Servers ermitteln.

Beispiel für einen Befehl:
ab -c 100 -n 100 http://testserver.com/

Apache Benchmark ist bei der Default- Installation von Apache dabei.



Desweiteren möchte ich auf memcache aufmerksam machen, ich selber habe zwar keine praktischen Erfahrungen mit dem Object- Cachingsystem, doch ich denke, dass es für HighLoad Anwendungen durchaus interessant ist.

Ich hoffe euch hat der Beitrag gefallen.

MFG

Andreas


Quellen:

http://eaccelerator.net/
http://www.xdebug.org/
http://www.mod-top.org/
http://forge.mysql.com/wiki/MySQL_Proxy
http://www.mysqlperformanceblog.com/
http://www.h07.org/projects/apachetuning/#21
http://www.danga.com/memcached/


Kommentare

by:

Hallo,

nach meinem Urlaub mal wieder ein kleiner Artikel zum Thema PHP.

Manchmal ist es nützlich einen in den Hintergrund zu legen, dies dient zum Beispiel dazu bei rechen- und zeitintensiven Prozessen den Benutzer nicht warten zu lassen.

Code

<?php shell_exec("nohup php /var/www/test.php > /dev/null 2> /dev/null & echo $"); ?>

Die PHP Funktion shell_exec führt eine shell Befehl aus.

nohup nabelt ein Programm vom Elternprozess ab

php -q /var/www/test.php führt den PHP Script aus, der im Hintergrund laufen soll.

> /dev/null leitet die Ausgabe ins Nirgendwo um.

Wenn also diese Zeile im Browser geöffnet wird, wird ein Subprozess von php gestartet, das bedeutet der Benutzer kann weitersurfen, während der Prozess auf dem Server weiter läuft.

Leicht ist das z.B. mit einer Endlosschleife zu testen.

Um sich aktive Prozesse am Server anzusehen genügt z.B. folgender shell Befehl:

ps aux | grep php

Ich hoffe der Beitrag hat euch gefallen und freue mich über euer Feedback.

MFG

Andreas


Kommentare

by:

Hallo,

nachdem ich die letzten Tage wenig neues veröffentlicht habe, heute mal etwas interessantes für den ambitionierten PHP Programmierer.

Eine PLZ Umkreissuche in PHP, dazu benötigen wir:

  1. Eine Geo DB mit Long und LAT sowie PLZ (am besten von opengeodb auf sourceforge)
  2. Einen brauchbaren Umkreissuchen-Script
  3. Etwas Zeit

Bei meinen Versuchen hat sich herausgestellt, dass ich die meiste Zeit damit verbracht habe, eine brauchbare Datenbank zu finden und zu formatieren. Hilfe dazu weiter unten, jetzt erstmal etwas Code:

Code

<?
// Zuerst eine Verbindung zur Datenbank aufbauen!
 $connect=@mysql_connect("localhost", "user", "pass")
or die("Cant connect to Database");
 @mysql_select_db("geo_plz", $connect)or die("Cant select Database");

// die PLZ nach der wir suchen
$plz = '9220';

// der Umkreis in Km
$umkreis = 5;

// Erdradius (geozentrischer Mittelwert) in Km
$radius = 6368;

/* -------------------------- */

$sql_rad = mysql_query("SELECT lon, lat FROM `plz_at` WHERE `plz` = '$plz' ");
$erg_rad = mysql_fetch_object($sql_rad);

// Umrechnung von GRAD IN RAD

$lon = $erg_rad->lon / 180 * M_PI;
$lat = $erg_rad->lat / 180 * M_PI;

// jetzt erfolgt die eigentliche Abfrage

$query = "SELECT ort, plz, (
 ".$radius." * SQRT(2*(1-cos(RADIANS(lat)) * 
 cos(".$lat.") * (sin(RADIANS(lon)) *
 sin(".$lon.") + cos(RADIANS(lon)) * 
 cos(".$lon.")) - sin(RADIANS(lat)) * sin(".$lat.")))) AS Distance 
 FROM plz_at WHERE 
 ".$radius." * SQRT(2*(1-cos(RADIANS(lat)) * 
 cos(".$lat.") * (sin(RADIANS(lon)) * 
 sin(".$lon.") + cos(RADIANS(lon)) * 
 cos(".$lon.")) - sin(RADIANS(lat)) * sin(".$lat."))) <= ".$umkreis." 
 ORDER BY Distance
";

// die Ausgabe (vereinfacht)

$sql = mysql_query($query);
while( $erg = mysql_fetch_object($sql) ) {

 echo '
<pre>', print_r($erg), '</pre>
';
}
?>


Natürlich wäre es jetzt denkbar für jede gefundene PLZ im Umkreis eine Abfrage der Mitglieder oder Filialen zu machen, diesen Spass überlasse ich aber lieber euch :)

Wer die formatierte Datenbank für Deutschland, Österreich und Schweiz braucht oder eine Frage hat, einfach kurz melden.

LG

Andreas

Eine wichtige Adresse die beim Erstellen der Datenbank sowie der Gestaltung der Abfrage hilfreich ist lautet:

http://opengeodb.giswiki.org/wiki/OpenGeoDB_-_Umkreissuche

[UPDATE]

Ich habe die Datenbank online gestellt, übernehme aber keine Garantie für Vollständigkeit und Richtigkeit.

http://www.codejungle.org/code/zip.sql.gz


Kommentare

by:

This are my first example for codejungle, it s a database session handler for php.

I got this example from php.net, but there was some small bugs i.e. on the read method.

more comming soon

Code

<?php
class Session {
    
// session-lifetime
    
public $lifeTime;
    function 
__construct ($db) {
        
// get session-lifetime
        
$this->lifeTime get_cfg_var("session.gc_maxlifetime");
           
// open database-connection
        
$this->mdb2 =& MDB2::factory($db);
        if (
PEAR::isError($this->mdb2)) {
            
$php_errormsg .= $this->mdb2->getMessage();
            
$php_errormsg .= $this->mdb2->getDebugInfo();
        }
        
session_set_save_handler(array(&$this'open'),
                                array(&
$this'close'),
                                array(&
$this'read'),
                                array(&
$this'write'),
                                array(&
$this'destroy'),
                                array(&
$this'gc'));
        
register_shutdown_function('session_write_close');
        
session_start();
           return 
true;
    }
    function 
open($savePath$sessName) {
        
// get session-lifetime
        
$this->lifeTime get_cfg_var("session.gc_maxlifetime");
        return 
true;
    }
    function 
close() {
        
$this->gc(ini_get('session.gc_maxlifetime'));
        
// close database-connection
        
return $this->mdb2->disconnect();
    }
    function 
read($sessID) {
        global 
$php_errormsg;
        
// fetch session-data
        
$query "
            SELECT session_data FROM sessions
            WHERE session = '
$sessID'
            AND session_expires >
        "
.time();
        
$result $this->mdb2->query($query);
        
// return data or an empty string at failure
        
if (MDB2::isError($result)) {
            
$php_errormsg .= $result->getMessage();
            
$php_errormsg .= $result->getDebugInfo ();
            return 
false;
        }
        list(
$value)=@$result->fetchrow();
        return 
$value;
    }
    function 
write($sessID,$sessData) {
        global 
$php_errormsg;
        
// new session-expire-time
        
$newExp time() + $this->lifeTime;
        
// is a session with this id in the database?
        
$query "
            SELECT * FROM sessions
            WHERE session = '
$sessID'
        "
;
        
$result $this->mdb2->query($query);
        
// if yes,
          
if($result->numRows()) {
        
// ...update session-data
            
$query "
                UPDATE sessions
                SET session_expires = '
$newExp',
                 session_data = '
$sessData'
                WHERE session = '
$sessID'
            "
;
          }
        
// if no session-data was found,
          
else {
            
// create a new row
            
$query "
                INSERT INTO sessions (
                     session,
                      session_expires,
                      session_data)
                VALUES(
                     '
$sessID',
                      '
$newExp',
                      '
$sessData')
            "
;
          }
        
$result $this->mdb2->exec($query);
        
// if something happened, return true
        
if (MDB2::isError($result)) {
            
$php_errormsg .= $result->getMessage();
            
$php_errormsg .= $result->getDebugInfo ();
            return 
false;
        } else {
            
// ...else return true
            
return true;
        }
    }
    function 
destroy($sessID) {
        global 
$php_errormsg;
        
// delete session-data
        
$query "
            DELETE FROM sessions
            WHERE session = '
$sessID'
        "
;
        
$opt_db="OPTIMIZE TABLE sessions";  
        
$result $this->mdb2->exec($query);
        
$resultopt $this->mdb2->exec($opt_db);
        
// if session was not deleted, return false,
         
if (MDB2::isError($result)) {
            
$php_errormsg .= $result->getMessage();
            
$php_errormsg .= $result->getDebugInfo ();
            return 
false;
         } else {
            
// ...else return true
            
return true;
        }
    }
    function 
gc($sessMaxLifeTime) {
        global 
$php_errormsg;
        
// delete old sessions
        
$query "
            DELETE FROM sessions
            WHERE session_expires <
        "
.time();
        
$result $this->mdb2->exec($query);
        
// return affected rows
        
if (MDB2::isError($result)) {
            
$php_errormsg .= $result->getMessage();
            
$php_errormsg .= $result->getDebugInfo ();
        }
        return 
$result;
    }
}
?>

If you have question pls just ask


Kommentare


Seiten: