<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TheGeek.de &#187; php</title>
	<atom:link href="http://thegeek.de/t/php/feed" rel="self" type="application/rss+xml" />
	<link>http://thegeek.de</link>
	<description>WordPress, PHP, JavaScript, Web 2.0, Gaming, Motorräder, Fotografie, Piratenpartei, Privates</description>
	<lastBuildDate>Tue, 09 Mar 2010 16:09:05 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Per RegEx geraden und ungeraden Tabellen-Zeilen ensprechende CSS-Klassen zuweisen</title>
		<link>http://thegeek.de/per-regex-geraden-und-ungeraden-tabellen-zeilen-ensprechende-css-klassen-zuweisen</link>
		<comments>http://thegeek.de/per-regex-geraden-und-ungeraden-tabellen-zeilen-ensprechende-css-klassen-zuweisen#comments</comments>
		<pubDate>Wed, 23 Dec 2009 12:12:04 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[tabellen]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=426</guid>
		<description><![CDATA[Wer vor dem Problem steht, dass ein Kunde bei einer Web-Anwendung unbedingt Tabellen-Zeilen mit wechselnden Farben je gerader und ungerader Zeile wünscht und dafür ca. 200 Kilobyte Quellcode überarbeiten müsste, der kann es sich ein wenig vereinfachen, wenn folgender Code vor der Ausgabe auf den auszugebenden Inhalt angewendet wird.
Das Skript durchsucht mit zwei kleinen Regular [...]]]></description>
			<content:encoded><![CDATA[<p>Wer vor dem Problem steht, dass ein Kunde bei einer Web-Anwendung unbedingt Tabellen-Zeilen mit wechselnden Farben je gerader und ungerader Zeile wünscht und dafür ca. 200 Kilobyte Quellcode überarbeiten müsste, der kann es sich ein wenig vereinfachen, wenn folgender Code vor der Ausgabe auf den auszugebenden Inhalt angewendet wird.<span id="more-426"></span></p>
<p>Das Skript durchsucht mit zwei kleinen Regular Expressions den Inhalt nach Tabellen und weist dann den Tabellen-Zeilen entsprechende Klassen (even/odd) zu. So können alle Tabellen per CSS formatiert werden. Klar leidet darunter die Performance etwas, aber sicherlich nicht viel mehr, als wenn ich in jeder Schleife in der eine Tabelle aufgebaut wird ein Zähler mitlaufen lasse und eine Bedingsabfrage mache.</p>
<pre class="brush:php">
	// Convert table rows to even/odd class
	preg_match_all( "/&lt;table.*&gt;(.*)&lt;\/table&gt;/siU", $html, $matches );
	if( $matches )
	{
		foreach( $matches[ 1 ] AS $tbody )
		{
			$new_rows = '';
			if( preg_match_all( "/&lt;tr.*&gt;.+&lt;\/tr&gt;/siU", $tbody, $tbmatches ) )
			{
				$i = 0;
				foreach( $tbmatches[ 0 ] AS $tr )
				{
					// Ignore rows containing th cells
					if( strpos( $tr, '&lt;th' ) === false )
					{
						if( $i % 2 == 0 )
							$new_rows .= str_replace( '&lt;tr', '&lt;tr class="even"', $tr );
						else
							$new_rows .= str_replace( '&lt;tr', '&lt;tr class="odd"', $tr );
						$i++;
					}
					else	$new_rows .= $tr;
				}
				$html = str_replace( $tbody, $new_rows, $html );
			}
		}
	}
</pre>
<p>Im Grunde ganz einfach: Die erste RegEx sucht alle vorhanden Tabellen und deren Inhalt. Danach werden die Zeilen des Inhalts ebenfalls per RegEx ermittelt und per Zeichenersetzung angepasst.</p>
<p>Vielleicht hilft das ja Jemandem irgendwann mal&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/per-regex-geraden-und-ungeraden-tabellen-zeilen-ensprechende-css-klassen-zuweisen/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spaß mit der Twitter API und Ausdruck des Protests gegenüber Harley Davidson</title>
		<link>http://thegeek.de/spas-mit-der-twitter-api-und-ausdruck-des-protests-gegenuber-harley-davidson</link>
		<comments>http://thegeek.de/spas-mit-der-twitter-api-und-ausdruck-des-protests-gegenuber-harley-davidson#comments</comments>
		<pubDate>Wed, 09 Dec 2009 12:54:30 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[buell]]></category>
		<category><![CDATA[harley davidson]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[protest]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=398</guid>
		<description><![CDATA[@moto1203 hat mich über Twitter kontaktiert und gefragt, ob es nicht irgendwie möglich sei ein Programm zu schreiben, dass bei bestimmten Hashtags eine @reply erzeugt. Thematisch ging&#8217;s konkret um den bekannten Motorradhersteller &#8220;Harley Davidson&#8221;, der kürzlich die Tochter- und Traditionsfirma &#8220;BUELL&#8221; einfach so dicht gemacht hat. Buell Motorräder wurden &#8220;nicht oft genug&#8221; verkauft, was aber [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://twitter.com/moto1203">@moto1203</a> hat mich über Twitter kontaktiert und gefragt, ob es nicht irgendwie möglich sei ein Programm zu schreiben, dass bei bestimmten Hashtags eine @reply erzeugt. Thematisch ging&#8217;s konkret um den bekannten Motorradhersteller &#8220;Harley Davidson&#8221;, der kürzlich die Tochter- und Traditionsfirma &#8220;BUELL&#8221; einfach so dicht gemacht hat. Buell Motorräder wurden &#8220;nicht oft genug&#8221; verkauft, was aber nichts daran ändert, das die Kisten ihren Markt hatten. Das fanden wir jedenfalls schon ziemlich kacke von Harley Davidson.</p>
<p>Also habe ich kurzerhand einen neuen Twitter-Account mit dem klangvollen Namen &#8220;<a href="http://twitter.com/subversives">@subversives</a>&#8221; erstellt und ein kleines PHP-Skript geschrieben, dass neue Tweets mit einem #harley Hashtag sucht und eine zufällig ausgewählte Antwort erstellt. Natürlich konfigurierbar. :-)<span id="more-398"></span></p>
<p>Dazu gibt es zwei kleine Funktionen. Die erste Funktion sucht Tweets nach einem bestimmten Suchbegriff:</p>
<pre class="brush:php">
// Twitter search api
function twt_search( $username, $password, $search, $since_id = 0, $rpp = 30, $page = 1 )
{
	// Curl init
	$curl = curl_init();

	// Curl basic settings
	curl_setopt( $curl, CURLOPT_URL, 'http://search.twitter.com/search.json' );
	curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
	curl_setopt( $curl, CURLOPT_USERPWD, "$username:$password" );
	curl_setopt( $curl, CURLOPT_POST, true );

	// Build POST parameters
	$post_arr = array();
	$post_arr[] = "q=" . urlencode( $search );
	if( !empty( $since_id ) )
		$post_arr[] = "since_id=" . $since_id;
	if( !empty( $rpp ) )
		$post_arr[] = "rpp=" . $rpp;
	if( !empty( $page ) )
		$post_arr[] = "page=" . $page;
	curl_setopt( $curl, CURLOPT_POSTFIELDS, implode( '&#038;', $post_arr ) );

	// Exec, set return
	$return = json_decode( curl_exec( $curl ) );

	// Close curl
	curl_close( $curl );

	return $return;
}
</pre>
<p>Übergeben werden Benutzername, Passwort, der Suchbegriff und &#8211; wenn bekannt &#8211; auch die &#8220;since_id&#8221;, welche es ermöglicht nur Tweets mit einer höheren ID zu ermitteln. Das ist für unser lustiges Protest-Skript wichtig, denn wir wollen die Leute ja nicht zuspammen und immer wieder auf die gleichen Tweets antworten. Nur neue Tweets seit der letzten Suche sollen berücksichtigt werden, also merken wir uns einfach die höchste Tweet ID und übergeben diese wieder bei der nächsten Suche. Der Parameter &#8220;rpp&#8221; steht übrigens für &#8220;results per page&#8221; &#8211; mit der Voreinstellung werden also maximal 30 Tweets zurückgegeben.</p>
<p>Technisch wird die Abfrage über die CURL-Bibliothek realisiert, theoretisch ginge es aber auch mit &#8220;file_get_contents&#8221; oder &#8220;fopen&#8221;, aber ich mag CURL. Ist ganz praktisch.</p>
<p>Die zweite benötigte Funktion erstellt über die Twitter API einen neuen Tweet. Auch hier stehen wieder einige Parameter zur Verfügung:</p>
<pre class="brush:php">
// Twitter update api
function twt_update( $username, $password, $status, $in_reply_to_status_id = '', $lat = '', $long = '' )
{
	// Curl init
	$curl = curl_init();

	// Curl basic settings
	curl_setopt( $curl, CURLOPT_URL, 'http://twitter.com/statuses/update.json' );
	curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
	curl_setopt( $curl, CURLOPT_USERPWD, "$username:$password" );
	curl_setopt( $curl, CURLOPT_POST, true );

	// Build POST parameters
	$post_arr = array();
	$post_arr[] = "status=" . urlencode( $status );
	if( !empty( $in_reply_to_status_id ) )
		$post_arr[] = "in_reply_to_status_id=" . $in_reply_to_status_id;
	if( !empty( $lat ) )
		$post_arr[] = "lat=" . $lat;
	if( !empty( $long ) )
		$post_arr[] = "long=" . $long;
	curl_setopt( $curl, CURLOPT_POSTFIELDS, implode( '&#038;', $post_arr ) );

	// Exec, set return
	$return = json_decode( curl_exec( $curl ) );

	// Close curl
	curl_close( $curl );

	return $return;
}
</pre>
<p>Neben Nutzername und Passwort können an diese Funktion der Statustext (Tweet) und der sehr wichtige Parameter &#8220;in_reply_to_status_id&#8221; übergeben werden. Wird die ID eines Tweets mit diesem Parameter übergeben, erkennt Twitter, dass es sich um eine @rely zu dem Tweet mit der übergebenen ID handelt. Da wir ja Antworten senden wollen, genau das richtige! Die Parameter &#8220;lat&#8221; und &#8220;long&#8221; sind übrigens nur schmückendes Beiwerk und werden von mir nicht genutzt. Ich habe das nur der Vollständigkeit halber mit rein genommen.</p>
<p>Nun zur Anwendung der Funktionen:</p>
<pre class="brush:php">
// Twitter account settings
$username = 'user';
$password = 'pass';

// Configure some reply variations in english and german
$replys_en = array(
	'Always remember #BUELL if you talk about Harley Davidson!',
	'Hey, remember #BUELL if you talk about Harley Davidson!',
	'Remember #BUELL FOREVER! Harley Davidson? NEVER!',
	'It makes me sick, that you dont talk about #BUELL ;-)',
	'#BUELL #BUELL #BUELL remember the Harley Davidson #FAIL',
	'#BUELL killed by Harley Davidson in 2k9. Remember that!',
	'#BUELL will never die. Harley Davidson will.'
);
$replys_de = array(
	'Erinner dich an #BUELL wenn du über Harley Davidson sprichst!',
	'Harley Davidson? Die Firma, die #BUELL zerstört hat?',
	'#BUELL FOREVER! Harley Davidson? NEVER!',
	'Es macht mich krank, dass nicht auch über #BUELL sprichst!',
	'#BUELL #BUELL #BUELL denk an den Harley Davidson #FAIL',
	'#BUELL wurde von Harley Davidson 2k9 geschlossen. HD is next!',
	'#BUELL wird niemals sterben, aber Harley Davidson. #Rentnerchopper'
);

// Load last parsed tweet id
if( file_exists( 'harley_since_id.dat' ) )
	$harley_since_id = file_get_contents( 'harley_since_id.dat' );
else
	$harley_since_id = 0;

// Search for tag harley
$harley = twt_search( $username, $password, '#harley', $harley_since_id );
if( is_object( $harley ) )
{
	if( count( $harley -> results ) )
	{
		foreach( $harley -> results AS $rkey => $tweet )
		{
			// Descending order, so the first array element has the highest id!
			if( $rkey == 0 )
				$harley_since_id = $tweet -> id;
			// Only reply if buell not found
			if( stripos( $tweet -> text, 'buell' ) === false &#038;&#038; $tweet -> from_user != $username )
			{
				if( $tweet -> iso_language_code != 'de' )
					$reply = "@{$tweet->from_user} " . $replys_en[ array_rand( $replys_en ) ];
				else
					$reply = "@{$tweet->from_user} " . $replys_de[ array_rand( $replys_de ) ];

				echo "$reply\n";

				// Send reply
				twt_update( $username, $password, $reply, $tweet -> id );
			}
		}
	}
	else	echo "No new tweets to tag #harley\n";
}

// Store last parsed tweet id
file_put_contents( 'harley_since_id.dat', $harley_since_id );
</pre>
<p>Zuerst werden in zwei Arrays englische bzw. deutsche Ausdrücke des Protests definiert, danach wird aus einer kleinen Datendatei die ID des letzten gefundenen Tweets geladen und die Suche ausgeführt.<br />
Die Suchfunktion gibt ein Objekt zurück, dass in der Eigenschaft &#8220;results&#8221; die gefundenen Tweets als Array enthält, welches anschließend durchlaufen wird. Beim ersten gefundenen Tweet wird die &#8220;since_id&#8221; neu gesetzt. Warum beim ersten? Na, weil die Tweets absteigend sortiert sind &#8211; der Erste ist also immer der Aktuellste.<br />
Enthält der Tweet nicht das Wort &#8220;buell&#8221;, wird in der entsprechenden Sprache (deutsch oder englisch) eine @reply an den Twitter-Account des Tweets gesendet.</p>
<p>Tja, das war&#8217;s eigentlich schon. Wer es mal probieren und einen Spruch reingedrückt bekommen will, der zwitschert einfach mal was mit dem Hashtag #harley &#8211; es dauert allerdings ein wenig, bis die Antwort kommt, das Skript läuft nur alle 15 Minuten.</p>
<p>Ich bin gespannt, wie lange der Account aktiv ist, ohne als Spam gemeldet zu werden. ;-)</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/spas-mit-der-twitter-api-und-ausdruck-des-protests-gegenuber-harley-davidson/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SOAP Dienste programmieren mit PHP</title>
		<link>http://thegeek.de/soap-dienste-programmieren-mit-php</link>
		<comments>http://thegeek.de/soap-dienste-programmieren-mit-php#comments</comments>
		<pubDate>Tue, 10 Nov 2009 13:28:11 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[soap]]></category>
		<category><![CDATA[web-service]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=323</guid>
		<description><![CDATA[Wer für seine eigene Anwendung eine Web-API anbieten möchte, hat vielfältige Möglichkeiten dies zu realisieren. Per einfachem HTTP GET oder POST Request und einer Rückgabe als XML/RSS/CSV/JSON/whatever, oder &#8211; was ich etwas eleganter finde &#8211; per SOAP. Dabei ist das Entwickeln eines eigenen SOAP Dienstes mit PHP gar nicht so kompliziert, wie vielleicht vermutet. Zumindest [...]]]></description>
			<content:encoded><![CDATA[<p>Wer für seine eigene Anwendung eine Web-API anbieten möchte, hat vielfältige Möglichkeiten dies zu realisieren. Per einfachem HTTP GET oder POST Request und einer Rückgabe als XML/RSS/CSV/JSON/whatever, oder &#8211; was ich etwas eleganter finde &#8211; per SOAP. Dabei ist das Entwickeln eines eigenen SOAP Dienstes mit PHP gar nicht so kompliziert, wie vielleicht vermutet. Zumindest finde ich SOAP schöner als die weitere Alternative XML-RPC.<span id="more-323"></span></p>
<p>Aber nun zur Definition von SOAP (Quelle: Wikipedia): SOAP (ursprünglich für Simple Object Access Protocol) ist ein Netzwerkprotokoll, mit dessen Hilfe Daten zwischen Systemen ausgetauscht und Remote Procedure Calls durchgeführt werden können. SOAP stützt sich auf andere Standards: XML zur Repräsentation der Daten und Internet-Protokolle der Transport- und Anwendungsschicht (vgl. TCP/IP-Referenzmodell) zur Übertragung der Nachrichten. Die gängigste Kombination ist SOAP über HTTP und TCP.</p>
<p>In der Praxis bedeutet das folgendes: In einer XML Datei (WSDL) werden Nachrichten-Typen definiert und an Operationen gebunden. Dabei gibt es Input-Nachrichten und Output-Nachrichten, sprich Übergaben und Rückgaben. Die WSDL Datei (WSDL = Web Services Description Language) wird dabei vom Client, als auch vom Server genutzt und regelt so die Kommunikation dieser beider Stellen.</p>
<p>Die Vorgehensweise um einen neuen Web-Service zu erstellen ist bei mir immer zuerst die WSDL zu erzeugen, danach die Operationen im Server abzubilden, um diese anschließend mit dem Client zu testen. Eine Beispiel WSDL könnte z.B. so aussehen:</p>
<pre class="brush:xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;definitions name=&quot;TheGeek&quot;
	targetNamespace=&quot;http://thegeek.de/wp-soap/thegeek.wsdl&quot;
	xmlns:tns=&quot;http://thegeek.de/wp-soap/thegeek.wsdl&quot;
	xmlns=&quot;http://schemas.xmlsoap.org/wsdl/&quot;
	xmlns:soap=&quot;http://schemas.xmlsoap.org/wsdl/soap/&quot;
	xmlns:xsd=&quot;http://www.w3.org/2001/XMLSchema&quot;&gt;

	&lt;!-- GET LATEST POSTS --&gt;
	&lt;message name=&quot;RequestGetPostsIn&quot;&gt;
		&lt;part name=&quot;apikey&quot; type=&quot;xsd:string&quot;/&gt;
		&lt;part name=&quot;num&quot; type=&quot;xsd:integer&quot;/&gt;
	&lt;/message&gt;
	&lt;message name=&quot;RequestGetPostsOut&quot;&gt;
		&lt;part name=&quot;returncode&quot; type=&quot;xsd:integer&quot;/&gt;
		&lt;part name=&quot;error&quot; type=&quot;xsd:string&quot;/&gt;
		&lt;part name=&quot;posts&quot; type=&quot;xsd:struct&quot;/&gt;
		&lt;part name=&quot;posts_count&quot; type=&quot;xsd:integer&quot;/&gt;
	&lt;/message&gt;
	&lt;portType name=&quot;RequestGetPosts_PortType&quot;&gt;
		&lt;operation name=&quot;GetPosts&quot;&gt;
			&lt;input message=&quot;tns:RequestGetPostsIn&quot;/&gt;
			&lt;output message=&quot;tns:RequestGetPostsOut&quot;/&gt;
		&lt;/operation&gt;
	&lt;/portType&gt;
	&lt;binding name=&quot;GetPosts_Binding&quot; type=&quot;tns:RequestGetPosts_PortType&quot;&gt;
		&lt;soap:binding style=&quot;rpc&quot; transport=&quot;http://schemas.xmlsoap.org/soap/http&quot;/&gt;
		&lt;operation name=&quot;GetPosts&quot;&gt;
			&lt;soap:operation soapAction=&quot;GetPosts&quot;/&gt;
			&lt;input&gt;
				&lt;soap:body
					encodingStyle=&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;
					namespace=&quot;urn:thegeek-getpostsservice&quot;
					use=&quot;encoded&quot;/&gt;
			&lt;/input&gt;
			&lt;output&gt;
				&lt;soap:body
					encodingStyle=&quot;http://schemas.xmlsoap.org/soap/encoding/&quot;
					namespace=&quot;urn:thegeek-getpostsservice&quot;
					use=&quot;encoded&quot;/&gt;
			&lt;/output&gt;
		&lt;/operation&gt;
	&lt;/binding&gt;
	&lt;service name=&quot;GetPosts_Service&quot;&gt;
		&lt;documentation&gt;Return latest posts&lt;/documentation&gt;
		&lt;port binding=&quot;tns:GetPosts_Binding&quot; name=&quot;GetPosts_Port&quot;&gt;
			&lt;soap:address location=&quot;http://thegeek.de/wp-soap/index.php&quot;/&gt;
		&lt;/port&gt;
	&lt;/service&gt;

&lt;/definitions&gt;
</pre>
<p>Diese WSDL definiert eine einfache Funktion &#8220;GetPosts&#8221; mit einer eingehenden Nachricht und einer ausgehenden Nachricht. Für die einzelnen Felder der Nachrichten sind entsprechende Typen definiert. Nachdem die Nachrichten an die Operation &#8220;GetPosts&#8221; gebunden wurden, wird mit dieser Operation ein Soap-Service definiert. Ein Service besteht also aus einem Binding, welches wiederum aus eine Input- und/oder Output-Message besteht. Das klingt nun zugegeben ziemlich kompliziert, ist aber in der Praxis wirklich einfach nachzuvollziehen, wenn wir uns mal den Server-Quellcode zu dieser WSDL Definition ansehen.</p>
<pre class="brush:php">
&lt;?php

// SOAP config array
$soap_config = array( 'encoding' =&gt; 'UTF-8' );

// Don't cache WSDL files, mandatory for development
ini_set( 'soap.wsdl_cache_enabled', '0' );

class thegeek_soapserver
{
	function __construct( $parameters )
	{

	}

	public function GetPosts( $apikey = '', $num = 10 )
	{
		if( $apikey == 'demoapikey' )
		{
			$posts = array( 	array( 'title' =&gt; 'Demo Post 1', 'body' =&gt; 'Demo content 1' ),
						array( 'title' =&gt; 'Demo Post 2', 'body' =&gt; 'Demo content 2' ),
						array( 'title' =&gt; 'Demo Post 3', 'body' =&gt; 'Demo content 3' ),
						array( 'title' =&gt; 'Demo Post 4', 'body' =&gt; 'Demo content 4' )
			);
			return array(	'return' =&gt; true,
					'error' =&gt; '',
					'posts' =&gt; $posts,
					'posts_count' =&gt; 0
			);
		}
		// API KEY FAIL
		else
		{
			return array(	'return' =&gt; false,
					'error' =&gt; 'API KEY INVALID',
					'posts' =&gt; array(),
					'posts_count' =&gt; 0
			);
		}
	}
}

// Run SOAP server
$soapserver = new SoapServer( 'http://thegeek.de/wp-soap/thegeek.wsdl', $soap_config );
$soapserver -&gt; setClass( 'thegeek_soapserver', 'some parameters for the constructor (example only...)' );
$soapserver -&gt; handle();

?&gt;
</pre>
<p>Nachdem die Soap-Config für die PHP Klasse &#8220;SoapServer&#8221; definiert und das caching von WSDL Dateien per &#8220;ini_set&#8221; ausgeschaltet wurde, folgt unsere eigene Klasse, die den Web-Service abbildet. Der Konstruktor kann wie gewohnt definiert werden, auch beim Initialisieren unserer Klasse über die PHP Klasse &#8220;SoapServer&#8221;, können beliebige Parameter übergeben werden. Übrigens sind auch extends problemlos möglich.</p>
<p>Dann findet sich in der Klasse eine Methode, welche unseren SoapService &#8220;GetPosts&#8221; abbildet, als Übergabeparameter sind die Variablen unserer Input-Nachricht angegeben. Wie die Variablennamen in der Methode gewählt werden ist egal, aber die Methode muss genau so heißen, wie in der WSDL angegeben (soap:operation soapAction=&#8221;GetPosts&#8221;). Der Code in der Methode dient natürlich nur der Verdeutlichung, wie Rückgaben erfolgen, nämlich als assoziatives Array, welches die in der WSDL definierte Output-Nachricht abbildet.</p>
<p>Um unsere Server-Klasse dann zu initialisieren, wird die PHP Klasse &#8220;SoapServer&#8221; mit entsprechenden Parametern (Web-Pfad zur WSDL, SoapConfig) aufgerufen. Danach wird mit Hilfe der Methode &#8220;setClass&#8221; unsere Klasse als Handler ausgewählt und der Server letztendlich mit der Methode &#8220;handle&#8221; konstruiert.</p>
<p>Fehlt eigentlich nur noch ein kleiner Test-Client:</p>
<pre class="brush:php">
&lt;?php

// Create new SOAP client
$soap_client = new SoapClient( 'http://thegeek.de/wp-soap/thegeek.wsdl', array( 'encoding' =&gt; 'UTF-8' ) );
if( is_object( $soap_client ) )
{
	$soap_result = $soap_client -&gt; GetPosts( 'demoapikey', 10 );
	// Debug output
	echo &quot;&lt;pre&gt;&quot;;
	print_r( $soap_result );
	echo &quot;&lt;/pre&gt;&quot;;
}
else	die( 'SOAP Server not available' );

?&gt;
</pre>
<p>Der Client ist ziemlich problemlos umzusetzen: Einfach mit der PHP Klasse &#8220;SoapClient&#8221; ein Client-Objekt erzeugen (Web-Pfad zur WSDL übergeben) und die Methoden (= Operationen) wie in der WSDL definiert nutzen. Obiges Beispiel gibt folgendes aus:</p>
<pre class="brush:plain">
Array
(
    [returncode] =&gt;
    [error] =&gt;
    [posts] =&gt; Array
        (
            [0] =&gt; Array
                (
                    [title] =&gt; Demo Post 1
                    [body] =&gt; Demo content 1
                )

            [1] =&gt; Array
                (
                    [title] =&gt; Demo Post 2
                    [body] =&gt; Demo content 2
                )

            [2] =&gt; Array
                (
                    [title] =&gt; Demo Post 3
                    [body] =&gt; Demo content 3
                )

            [3] =&gt; Array
                (
                    [title] =&gt; Demo Post 4
                    [body] =&gt; Demo content 4
                )

        )

    [posts_count] =&gt; 0
)
</pre>
<p>So schwierig ist das mit SOAP und PHP also nicht. Wichtig ist allerdings noch: PHP muss mit der Option &#8220;&#8211;enable-soap&#8221; kompiliert werden, um die SOAP Extension nutzen zu können. Alternativ kann aber auch das SOAP PEAR Paket genutzt oder auf die Klasse nuSoap zurückgegriffen werden.</p>
<p>Wer selbst mal von seinem Webspace aus testen will: <a href="http://thegeek.de/wp-soap/thegeek.wsdl">http://thegeek.de/wp-soap/thegeek.wsdl</a></p>
<p>Wer Fragen hat: Comments are open.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/soap-dienste-programmieren-mit-php/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SVN per PHP bedienen</title>
		<link>http://thegeek.de/svn-per-php-bedienen</link>
		<comments>http://thegeek.de/svn-per-php-bedienen#comments</comments>
		<pubDate>Mon, 26 Oct 2009 17:51:33 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=240</guid>
		<description><![CDATA[Da ich ja einige WordPress Plugins entwickele und ich mir die Zusammenarbeit mit dem WP SVN Server erleichtern wollte, habe ich für alle Plugins ein kleines PHP Script geschrieben, welche die Änderungen im SVN eincheckt. Klar ginge das auch über ein Shell-Script, aber die PHP Datei kann ich nicht nur auf der Konsole, sondern auch [...]]]></description>
			<content:encoded><![CDATA[<p>Da ich ja einige WordPress Plugins entwickele und ich mir die Zusammenarbeit mit dem WP SVN Server erleichtern wollte, habe ich für alle Plugins ein kleines PHP Script geschrieben, welche die Änderungen im SVN eincheckt. Klar ginge das auch über ein Shell-Script, aber die PHP Datei kann ich nicht nur auf der Konsole, sondern auch über den Browser aufrufen &#8211; manchmal ganz praktisch.</p>
<p>Wenn ich an einem Plugin also nur kleine Änderungen gemacht habe, die ich eben schnell ins Repository schubsen will, dann kopiere ich die geänderten Dateien einfach in den trunk, erhöhe die Version im SVN Script und rufe dieses anschließend auf. Die neue Version wird dann eingecheckt und der neue tag erstellt.</p>
<pre class="brush:php">
&lt;?php
	// Config
	$plugin_src	= '/home/www/example/src/article2pdf/';
	$svn_home	= '/home/www/example/src/article2pdf/svn/article2pdf/';
	$svn_trunk	= '/home/www/example/src/article2pdf/svn/article2pdf/trunk/';
	$svn_tags	= '/home/www/example/src/article2pdf/svn/article2pdf/tags/';
	$svn_user	= 'the_user';
	$svn_passwd	= 'the_password';

	// Version values
	$version	= '0.27';
	$message	= 'Adding some new functions.';

	// Set home for svn, important, or svn will not work!
	putenv( "HOME=$svn_home" );

	// Up
	echo passthru( "cd $svn_home ; svn up", $ret );
	if( $ret === 0 )
	{
		// Stat
		echo passthru( "cd $svn_home ; svn stat", $ret );
		if( $ret === 0 )
		{
			// Check in trunk
			echo passthru( "cd $svn_home ; svn ci --username $svn_user --password $svn_passwd -m '$message'", $ret );
			if( $ret === 0 )
			{
				// Copy new version to tag
				echo passthru( "cd $svn_home ; svn cp trunk tags/$version", $ret );
				if( $ret === 0 )
				{
					// Stat and check in new version
					echo passthru( "cd $svn_home ; svn stat", $ret );
					echo passthru( "cd $svn_home ; svn ci --username $svn_user --password $svn_passwd -m 'Tagging $version'", $ret );
				}
			}
		}
	}
?&gt;
</pre>
<p>Wichtig ist per putenv das HOME-Verzeichnis auf den Pfad zum SVN Verzeichnis zu setzen, da SVN über PHP sonst nicht funktioniert. SVN braucht zwingend im Environment eine passende HOME-Angabe. Diese Umgebungsvariable scheint aber standardmäßig von PHP nicht gesetzt zu sein.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/svn-per-php-bedienen/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Spielerei mit der Twitter API</title>
		<link>http://thegeek.de/spielerei-mit-der-twitter-api</link>
		<comments>http://thegeek.de/spielerei-mit-der-twitter-api#comments</comments>
		<pubDate>Mon, 26 Oct 2009 11:58:12 +0000</pubDate>
		<dc:creator>Marc</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://thegeek.de/?p=214</guid>
		<description><![CDATA[Kürzlich habe ich ein wenig mit der Twitter API gespielt. Ich wollte mal sehen, welche Follower meiner Follower auch mir folgen. Dazu habe ich mir eine kleine Funktion geschrieben die ermittelt, welche anderen Twitterer von einem Account verfolgt werden. Die Ergebnisse habe ich in einer Datenbank-Tabelle gespeichert und später ausgewertet.
Die Funktion ist zwar nicht perfekt, [...]]]></description>
			<content:encoded><![CDATA[<p>Kürzlich habe ich ein wenig mit der Twitter API gespielt. Ich wollte mal sehen, welche Follower meiner Follower auch mir folgen. Dazu habe ich mir eine kleine Funktion geschrieben die ermittelt, welche anderen Twitterer von einem Account verfolgt werden. Die Ergebnisse habe ich in einer Datenbank-Tabelle gespeichert und später ausgewertet.</p>
<p>Die Funktion ist zwar nicht perfekt, mir reichte sie jedoch.</p>
<pre class="brush:php">
&lt;?php
function get_friends( $screen_name, $page_limit = 200 )
{
	$screen_names = array();
	for( $page = 1; $page < $page_limit; $page++ )
	{
		ob_start();
		$friends_json = file_get_contents( 'http://twitter.com/statuses/friends.json?screen_name=' . $screen_name . '&#038;page=' . $page );
		$errors = ob_get_contents();
		ob_end_clean();
		if( $friends_json !== false )
		{
			$friends = json_decode( $friends_json );
			if( is_array( $friends ) &#038;&#038; count( $friends ) )
			{
				foreach( $friends AS $friend )
					$screen_names[ $friend -> id ] = $friend -> screen_name;
			}
			else
			if( !count( $friends ) )
			{
				break;
			}
			else
			{
				$screen_names = array();
				break;
			}
		}
		else	break;
	}
	if( count( $screen_names ) || $errors == '' )
	{
		return $screen_names;
	}
	else
	{
		if( strpos( $errors, '401 Unauthorized' ) !== false )
			return false;
		else
			return null;
	}
}

// Example usage
print_r( get_friends( 'motorradblogger' ) );
?&gt;
</pre>
<p>Schade übrigens, dass die Anzahl der Requests pro Stunde bei Twitter limitiert ist, sonst ließen sich ziemlich schnell, ziemlich viele Twitter-Accounts crawlen. ;-)</p>
<p>Die Benutzung ist sehr simpel: Einfach den Accountnamen übergeben, die Funktion läd Seitenweise alle Accounts, denen gefolgt wird und gibt diese in einem assoziativen Array (Schlüssel: Account-ID, Wert: Accountname) zurück. Im Falle eines Fehlers wird &#8216;false&#8217; zurückgegeben, bei einem unbekannten Fehler &#8216;null&#8217;.</p>
]]></content:encoded>
			<wfw:commentRss>http://thegeek.de/spielerei-mit-der-twitter-api/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
