Quassel – PHP_search

Ich nutze ja schon eine Weile lang Quassel-IRC. Leider durchsucht die Suche nur das bereits vorhandene Backlog (bzw. die “Chathistorie”) und man muss immer erst mühsam bis zum Anfang hochscrollen, damit er sich “mehr” holt.

Jetzt hab ich einfach auf dem Server auf dem der Core läuft folgendes PHP-Script hinterlegt:

#!/usr/bin/php -q
<?php
$shortopts  = "";
$shortopts .= "h:";
$shortopts .= "u:";
$shortopts .= "c:";
$shortopts .= "s:";

$options = getopt($shortopts);

function getMessage($db, $quasseluser, $channel, $search = null) {
    $quasseluser = sqlite_escape_string($quasseluser);
    $channel = sqlite_escape_string($channel);
    $search = sqlite_escape_string($search);

    $sql = '
        SELECT DISTINCT
                backlog.time AS time,
                sender.sender AS sender,
                backlog.message AS message,
                buffer.buffername AS buffername
        FROM backlog
        OUTER JOIN quasseluser, buffer, sender
        ON (
                quasseluser.username = "'.$quasseluser.'"
                AND
                backlog.bufferid = buffer.bufferid
                AND
                quasseluser.userid = buffer.userid
                AND
                buffer.buffername LIKE "%'.$channel.'%"
                AND
                sender.senderid = backlog.senderid
        )';
    if ($search != null) {
        $sql .= ' WHERE message LIKE "%'.$search.'%";';
    }
    $output = array();
    $longestname = 0;
    foreach ($db->query($sql) as $row) {
        $sender = explode("!", $row['sender']);
        $sendername = $sender[0];
        if (strlen($sendername) > $longestname) {
            $longestname = strlen($sendername);
        }
        array_push(
            $output,
            array(
                date("Y-m-d H:i:s", $row['time']),
                $row['buffername'],
                $sendername,
                $row['message']
            ));
    }
    foreach ($output as $entry) {
        printf("%s (%s) %s : %s\n", $entry[0], $entry[1], str_pad($entry[2], $longestname, " "), $entry[3]);
    }
    printf("Es wurden %u Ergebnisse gefunden.\n", count($output));
}

try {
    $homepath = $options["h"];
    $username = $options["u"];
    $buffer = $options["c"];
    $search = $options["s"];

    if(!$homepath || !$username || !$buffer) {
        $output = "usage: ";
        $output .= __FILE__." -h <path/to/quassel/sqlite> -u <quasseluser> -c <channel/buffer> [-s <string>]";
        die($output . "\n");
    }

    $db = new PDO('sqlite:' . $homepath);
    getMessage($db, $username, $buffer, $search);

} catch (PDOException $e) {
    echo 'Connection failed: ' . $e->getMessage();
}

Keinerlei Fehlerbehandlung, wenns schiefläuft geht bestimmt irgendwas irreperabel kaputt. Keine Garantie für nichts :) Ein möglicher Aufruf wäre:

14:34:46 pennywise ~# ./searchQuassel.php -h quassel-storage.sqlite -u pennywise -c quassel.de -s foobar
2008-11-03 11:49:01 (#quassel.de) pennywise    : und da war der Bot jetzt halt drin, weil er irgendwas gesagt hat wie "hallo foobar, wilkkommen in der hölle"
2008-11-06 20:35:57 (#quassel.de) pennywise    : kann ich auch ein temporäres netzwerk haben? sowas wie /join irc.server.com/#foobar?
2008-11-12 11:52:56 (#quassel.de) hanswurst    : im core-log steht nur "foobar benutzer x getrennt"

manpage

-h : Pfad zur SQLite-DB von quasselcore. Liegt meist in ~/.config/quassel-irc.org/
-u : Der Benutzer mit dem man sich in quassel einloggt. Dies hat nichts mit der IRC-Identität zu tun.
-c : Der Channel (bzw. das Query) in dem gesucht werden soll. Ist case insensitive und kann auch nur teilweise übergeben werden (z.B. "quassel" findet "#quassel", "#quassel.de" und "quassel-announce")
-s : OPTIONAL. Der Text nach dem gesucht werden soll. Wenn weggelassen, dann werden alle Nachrichten im übergebenen Channel zurückgegeben

Ich hatte auch noch ne Version mit Prepared Statements, aber die hat beim "$db->prepare($sql)" einfach kein Statement erzeugt. Ohne Fehlermeldung ohne alles. WTF?!

Scienta ZF Debug Bar

Der Firefox und seine diversen Erweiterungen. Es gibt mit Firebug und FirePHP schon exzellente Tools zur Entwicklung mit PHP und jetzt gibt es noch ein Weiteres:

Scienta ZF Debug Bar

Der aufmerksame Leser hat hier ZF entdeckt und, ja tatsächlich, hier ist die Rede vom Zend Framework.

2009scienta-debugbar.png

Die Toolbar erlaubt es einem die SQL-Queries, die Page-Render-Zeit, die Version des ZF und den Speicherverbrauch anzuzeigen. Und noch ein paar Gimmicks mehr, dazu verweise ich aber einfach auf den Original-Blogeintrag.

Quelle: http://jokke.dk/blog/2009/01/introducing_the_scienta_zf_debug_bar

PHP hates me – eine Set-Klasse

Kommentare gesperrt, weil dieses Posting Spambots magisch anzieht.

Mir ist aufgefallen, daß meine Klasse nicht abfängt wenn man zweimal dasselbe Objekt ins Set setzt. Deshalb ein kleines Update

Nils Langner von PHP hates me hat eine Aufgabe gestellt. Und hier meine spontane Lösung, vom Hirn ins Terminal :)

<?php
<div class="moz-text-plain" style="font-family: -moz-fixed; font-size: 13px;" lang="x-western">
<pre>class Foobar {
}

/**
 * @author Matthias Coy
 */
class Set {
    private $set = null;
    private $typ = null;
    private $className = null;

    /**
     * The method to add something to the set. The type of the set is defined by its first entry.
     * @param <type> $something
     * @public
     */
    function push($something) {
        if ($this->set == null) {
            $this->typ = gettype($something);
            $this->set = array();
            array_push($this->set, $something);
            if($this->typ == "object") {
                $class = new ReflectionClass($something);
                $this->className = $class->getName();
                echo "It's a class, with the name: '".$this->className."'\n";
            } else {
                echo "It's something else: '". $this->typ ."'";
            }
        } else {
            $myType = gettype($something);
            if($myType != $this->typ) {
                throw new Exception("Wrong Type, this set is a set of '".$this->typ."'");
            } else {
                if ($myType == "object") {
                    $class = new ReflectionClass($something);
                    if ($this->className != $class->getName()) {
                        throw new Exception("Right Type, but wrong class (is: '".$class->getName()."', should be: '".$this->className."')");
                    }
                    foreach($this->set as $entry) {
                        if ($something === $entry) {
                            throw new Exception('Right Type, but already in Set');
                        }
                    }
                }
                array_push($this->set, $something);
                echo "adding sth. (".$myType.")\n";
            }
        }
    }

    /**
     * Return the last inserted entry of the set.
     *
     * @return <type>
     * @public
     * @throws Exception if set is empty
     */
    function pop() {
        $returnValue = array_pop($this->set);
        if ($returnValue == null) {
            $this->set = null;
            $this->typ = null;
            $this->className = null;
            throw new Exception("Set is not yet defined, please add something first");
        }
        return $returnValue;
    }

    /**
     * Returns the amount of entries in the set
     *
     * @return <type> Entry of the set
     * @public
     */
    function count() {
        return count($this->set);
    }
}

$var1 = new Set();
$var2 = new Foobar();

$mySet = new Set();
$mySet->push($var1);
try {
    // Add something that is different to the types already in the set
    $mySet->push($var2); // throws execption
} catch (Exception $e) {
    print $e->getMessage()."\n";
}
try {
    // Add something which has the right type, but is already inside the set
    $mySet->push($var1); // throws execption
} catch (Exception $e) {
    print $e->getMessage()."\n";
}
while($mySet->count() > 0) {
    $mySet->pop();
}
$mySet->push($var2);
try {
    $mySet->push($var1);
} catch (Exception $e) {
    print $e->getMessage()."\n";
}
/* Output:
It's a class, with the name: 'Set'
Right Type, but wrong class (is: 'Foobar', should be: 'Set')
Right Type, but already in Set
It's a class, with the name: 'Foobar'
Right Type, but wrong class (is: 'Set', should be: 'Foobar')
 */
Veröffentlicht in PHP | Gekennzeichnet mit ,

PHP – SPL

Ein neuer schöner Überblick über die SPL (Standard PHP Library) gibts unter

  • http://www.phpro.org/tutorials/Introduction-to-SPL.html
Veröffentlicht in PHP | Gekennzeichnet mit ,

empty vs. isset vs. array_key_exists

Ich zitier hier einfach mal. Hab ich nämlich nicht gewusst.

The problem is that there are situations where isset() and empty() are
not appropriate checks. For instance, try this:

$test = array('foo' => null);
echo ((isset($test['foo'])) ? 'true' : 'false'); // echoes 'false'!

What about empty()?

$test = array('foo' => null);
echo ((empty($test['foo'])) ? 'true' : 'false'); // echoes 'true'
echo ((empty($test['bar'])) ? 'true' : 'false'); // also echoes 'true'!

What does that mean? It means that if you want to test for the presence
of a key, you can’t rely on isset() *or* empty()! array_key_exists() is
the only way to reliably verify that the key is present in the array.

$test = array('foo' => null);
echo (array_key_exists('foo', $test) ? 'true' : 'false'); // echoes 'true'
echo (array_key_exists('bar', $test) ? 'true' : 'false'); // echoes 'false'

Quote von Matthew Weier O’Phinney, Zend Framework Developer

__FUNCTION__ in Java

Unter PHP gibt es sogenannte Magische Konstanten. Die sind prima, wenn man z.B. eine Debugfunktion schreiben will, die an bestimmten Stellen sagt wo sie aufgerufen wurde. In Java sieht das dann so aus:

class Debug
{
  public static void print(String msg)
  {
    java.lang.Exception e = new java.lang.Exception();
    StackTraceElement ste[] = e.getStackTrace();
    System.out.println(
        new Date().getTime() + " " +
        ste[1].getClassName() + " " +
        ste[1].getMethodName() + " " +
        msg);
  }
}

Wird aufgerufen mit:

import mein.tolles.package.Debug;
Debug.print("lalala");

Was hiermit nicht geht ist: getFileName() und getLineNumber(), da diese Information nicht zur Verfuegung steht.

GnuPG mit PHP

Also, ich mag RoundCube Webmail. Allerdings fehlt mir (wie eigentlich in jedem Webmailer) eine Moeglichkeit E-Mails zu verschluesseln. Kurz zur Erklaerung: GnuPG ist ein Programm zur Verschluesselung und/oder Signierung von Daten. Dies koennen prinzipiell E-Mails, Dateien oder sonst irgendwas sein, wir befassen uns aber mal nur mit den E-Mails. GnuPG nutzt ein sogenanntes ‘Asymmetrisches Kryptosystem‘, d.h. jeder Benutzer dieser Systeme hat eine privaten und einen oeffentlichen Schluessel. Asymmetrisch bedeutet hier also, das wir nicht denselben Schluessel verwenden um etwas zu verschluesseln und es danach wieder zu entschluesseln.

weiterlesen