Schlagwort-Archiv: php

Wie suche ich in einem Array nach einem Textteil mit PHP?

Diese Herausforderung hatte ich jüngst zu meistern. Ursprung war eine recht unsinnige Datenbankstruktur bei einem Kunden. Dort gibt es keine Normalisierung im Datenbankuniversum 🙁

Aber nun genug gejammert. Auch damit muss man als Programmierer klar kommen. Die Problemstellung ist, dass eine Hierarchie durch eine Zeichenfolge in einem Textfeld angegeben wird. Dabei können mehrere Hierarchien auftreten, die ebenfalls durch ein Zeichen getrennt werden. Das sieht dann so aus:

2|15;2|8

Das Trennzeichen verschiedener Hierarchiedefinitionen ist das „;“ (Semikolon). Die Hierarchieebenen werden mit dem „|“ (Pipe) getrennt. Obige Darstellung signalisiert also ein Element, welches sich einmal in Hierarchie „2“ -> „15“ und einmal in Hierarchie „2“ -> „8“ befindet. Die Hierarchieebene „2“ ist also eine Oberebene und besitzt mindestens zwei Unterebenen.

Nun wird diese Hierchie für eine Verlinkung genutzt. Da ist es natürlich sehr passend, wenn man den Link abhängig von den Hierarchieebenen zusammenbaut. Befinde ich mich gerade in der Ebene „15“, dann will ich auch den Link via „2“ -> „15“ erhalten und in Ebene „8“ eben umgekehrt.

Nach kurzem Suchen fand ich dann die Lösung:

function array_find($haystack, $needle)
{
	$iterator = create_function('$item', 'return strpos($item, \''.$needle.'\')!==false;');
	return array_filter($haystack, $iterator);
}

function array_contains($haystack, $needle)
{
	$iterator = create_function('$value, $item', 'return $value or strpos($item, \''.$needle.'\')!==false;');
	return array_reduce($haystack, $iterator, false);
}

Diese beiden Funktionen liefern einmal ein Array mit den gefundenen Elementen. Die andere ein Boolean, ob das gesuchte Element sich irgendwo in den Werten befindet.

Hier ein Beispiel der Anwendung:

$needle = 'foo';
$array = array('affe', 'barfoos', 'cherry', 'dilemma', 'eisberg', 'fastfood');

printf('Das Array enthält irgendwo den String "%s": [%s]'.PHP_EOL, $needle, array_contains($array, $needle) ? 'X' : '-');
printf('Die folgenden Elemente enthalten den String "%s": [%s]'.PHP_EOL, $needle, implode(',', array_find($array, $needle)));

Die Ausgabe sieht dann so aus:

Das Array enthält irgendwo den String "foo": [X]
Die folgenden Elemente enthalten den String "foo": [barfoos,fastfood]

Mit diesen Funktionen konnte ich nun sehr elegant – ohne Schleife – die Herausforderung bewältigen. Danke Google, Klamm und tleilax.

Zend_XmlRpc_Server debuggen – so gehts!

Also ich hatte jetzt gerade wieder das Problem, dass mein GSales_Connector (XMLRPC-Schnittstelle zu GSales mit sehr erweitertem Funktionsumfang im Vergleich zur normalen Schnittstelle von GSales) ein wenig herumgezickt hat. Er lieferte Sachen wie folgendes:

Exception: Failed to parse response
~~ /[..]/library/Zend/XmlRpc/Client/ServerProxy.php@93: Zend_XmlRpc_Client->call(string, array)
~~ /[..]/library/GSales/SeriesInvoice.php@144: Zend_XmlRpc_Client_ServerProxy->updateSeriesInvoicePosition(integer, array)

Nun dachte ich mir so, dass ich zum debuggen einfach mail() nutzen könne. Pustekuchen…nicht mal Dateien hat der nette Zend_XmlRpc_Server geschrieben. Aber die Lösung des Problems ist so einfach, wie nützlich…leider kam ich nicht gleich darauf (muss wohl an der Uhrzeit liegen).

Meine Lösung:

  1. Zum Test einen kleinen Zend_XmlRpc_Client erstellen
  2. Die „kaputte“ Methode im Server mit einem weiteren @return-Typ versehen: string
  3. in der „kaputten“ Methode auf dem Server einfach per return „zeilenweise“ die Zwischenergebnisse zurückgeben lassen
  4. gefundenen Fehler fixen und vóila, alles ist schön

Hier mein Testclient (mit HTTP-Auth):

set_include_path('/pfad/zur/zf/library/');

require_once('Zend/Http/Client.php');
require_once('Zend/XmlRpc/Client.php');
require_once('Zend/Debug.php');
require_once('Zend/Http/Client/Exception.php');

$url = 'http://xmlrpc-server.loc/xmlrpc.php';
$username = 'httpauth-user';
$password = 'httpauth-password';

$httpClient = new Zend_Http_Client($url);
$httpClient->setAuth($username, $password);

$client = new Zend_XmlRpc_Client($url, $httpClient);
$proxy = $client->getProxy('module');

$intId = 123;
$arrUpdateData = array(
 'bez3' => 'klappt doch mit Ümlauten',
);

$strUpdateData = http_build_query($arrUpdateData);

Zend_Debug::dump($proxy->kaputteMethode($intId, $strUpdateData));

Und hier ist ein Auszug aus der xmlrpc.php vom Server:

/**
 * updates anything
 * @param int $pid
 * @param string $strUpdateData
 * @return bool|string
 */
function kaputteMethode($pid, $strUpdateData)
{
 parse_str($strUpdateData, $arrUpdateData);
 [..]
 return print_r($arrUpdateData, true);
}

$server = new Zend_XmlRpc_Server();
$server->addFunction('kaputteMethode', 'module');
echo $server->handle();

Also mir hat das sehr gut geholfen und leider fand ich bisher mit Google nichts dazu. Wer es anders macht oder besser kann, immer her damit! Was mich auch interessieren würde ist, ob ich mit dem Observer oder einer weiteren Exception-Definition per Zend_XmlRpc_Server_Fault etwas ähnliches hätte erreichen können. Ich glaube nicht, weiß es aber nicht so genau.

Umlaute mit strtoupper() gehen nicht

Das tolle an php ist ja eigentlich seine Einfachheit…aber manchmal könnte ich es an die Wand klatschen.

Folgender Quellcode bringt kein großes „Ä“:

echo strtoupper('ä');

Folgender Quellcode hingegen schon:

$s = strtoupper('ä');
$s  = strtr($s, array(
	'ä' => 'Ä',
	'ö' => 'Ö',
	'ü' => 'Ü',
));
echo $s;

Tja, das kann schon echt nervig sein.