PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Twitter-Applikationen mit Zend_Oauth

with 12 comments

Kurz vorab: Ich möchte mich bei euch Lesern bedanken, ihr habt mich dazu gebracht hier nun den 100. Artikel zu verfassen. Außerdem folgen mir aktuell 98 Leute bei Twitter (vielleicht werden es ja heute 100?), wenn das kein Grund zu feiern ist! Danke euch dafür! Doch nun gehts los:

In den Kommentaren zu meinem Artikel über das Twittern via PHP wurde ich darum gebeten die Twitter-API-Benutzung auch mittels OAuth zu zeigen. Das werde ich hier nun tun, mit einer kleinen Erklärung zu OAuth und dann natürlich auch PHP-Code.

Doch was ist OAuth? Normalerweise nutzt man zur API-Kommunikation die Twitter-Login-Informationen. Nehmen wir an wir wollen einen kleinen Dienst im Internet anbieten, den andere Leute nutzen können. Dabei soll unser Dienst auf den Account der Nutzer zugreifen und Daten auslesen oder gar verändern. Damit wir den Dienst umsetzen können müssen unsere Nutzer also ihre Login-Usernamen und Passwörter bei uns eintragen. Damit verfügen wir über die volle Kontrolle über diese Accounts, könnten sie also auch löschen, das Passwort ändern usw. Da sicherheitsbewusste Benutzer ihr Passwort nicht hergeben, wird niemand unseren Dienst nutzen. Von dem Problem, dass der Nutzer bei einem Passwortwechsel auch alle Applikationen in Kenntnis setzen müßte mal ganz abgesehen.

OAuth ist nun eine Möglichkeit, unserer Applikation begrenzten Zugang zu den Accounts zu geben, aber nicht mittels dem normalen Login-Passwort, sondern einem extra Passwort (Access-Token) für die Kombination aus unserer Applikation und dem Nutzerkonto. Dieser Zugang kann dann auch beschränkt werden zum Beispiel auf nur lesenden Zugriff. Außerdem kann der Zugang wieder entzogen werden. Der Accountbesitzer behält also die volle Kontrolle über seinen Account.

Unser Vorgehen sieht nun wie folgt aus:

  1. Unsere Applikation benötigt von Twitter einen sogenannten Consumer-Key und ein Consumer-Secret. Das müssen wir uns von Twitter besorgen und identifiziert unsere Applikation später beim Token-Austausch. Außerdem wird beides dann zu einer Art Verschlüsselung beim Token-Austausch genutzt.
  2. Nachdem der potentielle Nutzer nun auf unsere Webseite gegangen ist müssen wir uns für ihn einen Token besorgen. Dazu holen wir uns einen temporären unauthorisierten Token von Twitter.
  3. Mit diesem unauthorisierten Token leiten wir den User auf eine Seite von Twitter, wo er dann gefragt wird, ob er unserer Applikation den begrenzten API-Zugriff erlauben möchte. Falls er das tut, wird er zurück auf unsere Seite geleitet
  4. Wir erhalten nun den authorisierten Token, den wir in einer Datenbank abspeichern. Ab jetzt können wir auf das Nutzerkonto zugreifen, und der Nutzer hat seine Twitter-Logininformation nicht preisgeben müssen.

Da diese OAuth-Kommunikation standardisiert ist und im Detail auch etwas komplizierter, werden wir das nicht selbst implementieren sondern die Zend_Oauth-Klasse nutzen. Seit Zend Framework 1.10 ist diese im Lieferumfang enthalten. Es gibt auch noch weitere OAuth-Klassen, die genutzt werden können. Danach werden wir in Zusammenspiel mit Zend_Service_Twitter auf den Account zugreifen und einen Tweet absetzen.

Fangen wir also an:

Um den Consumer-Key und das Consumer-Secret zu erhalten registrieren wir unsere neue Applikation: http://twitter.com/oauth_clients

Wir benötigen auch Write-Rechte, da wir ja einen Tweet absetzen möchten. Nach erfolgreicher Applikationsregistrierung erhalten wie die besagten beiden Informationen:

Nun schreiben wir unsere kleine Testapplikation. Darin sind die Punkte 2-4 abgehandelt. Der Einfachkeit halber speichern wir den ACCESS_TOKEN nur in der Session, normalerweise würde man diesen zu den Nutzerinformationen in die Datenbank schreiben.

<?php
session_start();

require_once 'Zend/Oauth/Consumer.php';

$options = array(
        'callbackUrl'    => 'https://www.phpgangsta.de/twitter.php',
        'siteUrl'        => 'http://twitter.com/oauth',
        'consumerKey'    => '4c2jXXXXXXXXXXXXXXBkw',
        'consumerSecret' => 'iPkXiOXXXXXXXXXXXXXXXXXXXXXXbSAJRhE',
);

$consumer = new Zend_Oauth_Consumer($options);

if (!isset($_SESSION['ACCESS_TOKEN'])) {
    if (empty($_GET)) {
        $token = $consumer->getRequestToken();
        $_SESSION['REQUEST_TOKEN'] = serialize($token);
        $consumer->redirect();
    } else {
        $token = $consumer->getAccessToken($_GET, unserialize($_SESSION['REQUEST_TOKEN']));
        $_SESSION['ACCESS_TOKEN'] = serialize($token);
        unset($_SESSION['REQUEST_TOKEN']);
    }
}

if (isset($_SESSION['ACCESS_TOKEN'])) {
    $token = unserialize($_SESSION['ACCESS_TOKEN']);
    $client = $token->getHttpClient($options);

    require_once 'Zend/Service/Twitter.php';
    $twitter = new Zend_Service_Twitter();
    $twitter->setLocalHttpClient($client);
    $response = $twitter->status->update('Nachricht gesendet authentifiziert via OAuth');
}

Der Ablauf ist klar und wie oben beschrieben: Das Script holt sich einen Request-Token, der Nutzer wird dann auf die Twitter-Seite redirected und gefragt ob er den Zugriff erlauben möchte. Danach kommt er zurück auf unsere Seite (die wir bei der Registrierung angegeben haben, man kann diese auch mit dem Request abändern), wir holen uns aus den GET-Parametern den ACCESS_TOKEN und speichern ihn (in der Session). Danach können wir den TOKEN nutzen um zu twittern.

Dazu können wir entweder die oben beschriebene Methode nutzen und mit Hilfe des $token einen Http_Client erstellen den wir dann an den Twitter-Service geben. Dieser Client erledigt das Mitsenden der OAuth-Informationen bei jedem Request automatisch für uns. Oder aber wir nutzen den Http_Client direkt:

$client = $token->getHttpClient($options);
$client->setUri('http://twitter.com/statuses/update.json');
$client->setMethod(Zend_Http_Client::POST);
$client->setParameterPost('status', 'Nachricht gesendet authentifiziert via OAuth');
$response = $client->request();

Natürlich kann man die vergebenen Berechtigungen an Applikationen auch zurückziehen. Das geht auf der Seite https://twitter.com/account/connections:

Das war es auch schon für heute, ich hoffe das Prinzip von OAuth ist etwas klarer geworden und ihr könnt den Code nutzen um eigene Twitter-Applikationen zu erstellen.

Hier noch einige interessante Links zu (englischsprachigen) Tutorials und Übersichtsseiten:

Written by Michael Kliewe

März 14th, 2010 at 2:54 pm

Posted in PHP

Tagged with , , , ,

Linkpool Nummer 3

without comments

Interessante Vorstellung, Maßnahmen zu ergreifen innerhalb von 3 Minuten, um den Server zu retten während er überrannt wird:
http://www.stochasticgeometry.ie/2010/03/10/performance-tuning-a-server-in-three-minutes-while-being-slashdotte/

Schöne Übersicht von Ralf Eggert zum Zend Framework 2.0 Fortschritt:
http://blog.zf-info.de/2010/03/11/die-entwicklung-vom-zend-framework-2-0-hat-begonnen/

Interessantes Webinar am 17.03.2010 zu den Neuerungen von Zend Framework 1.10, mit Matthew Weier O’Phinney und Ralph Schindler:
http://devzone.zend.com/article/11954-Webinar—New-in-Zend-Framework-1.10

Noch ein interessantes Webinar am 17.03.2010 der „Velocity Online Conference“:
http://en.oreilly.com/velocity-mar2010

Kurze und gute Übersicht über Namespaces für diejenigen, die es noch nicht kennen, incl. Code:
http://pehbehbeh.de/webentwicklung/php/namespaces-grundlagen/

Cheat Sheet für das Zend Framework (6 Seiten):
http://refcardz.dzone.com/refcardz/getting-started-zend-framework?oid=hom19239

Written by Michael Kliewe

März 13th, 2010 at 12:35 pm

Posted in Allgemein

IMAP-Emails lesen mit dem Zend Framework

with 5 comments

Emails werden nicht nur von Menschen für Menschen geschrieben, sie werden auch häufig zur asynchronen Kommunikation zwischen Rechnern und Programmen eingesetzt.

In der Vergangenheit habe ich bereits einige Scripte geschrieben die Emails periodisch abholen und bearbeiten. Darunter waren zum Beispiel Backup-Benachrichtigungen von einem Programm das früher nicht in der Lage war, die Ergebnisse in eine Datenbank zu schreiben. Um eine Übersicht über einen Zeitraum zu erhalten muß man die Ergebnisse also per Email in ein Postfach senden lassen und dieses periodisch abrufen und die Emails parsen.

Ein anderes Script hat zum Beispiel ein Postfach nach Anhängen durchsucht. Dieses Postfach wurde dazu benutzt, Dokumente automatisiert verarbeiten zu lassen. Dazu wurden die Emails geparst, die Anhänge gelöst und dann je nach Absender an einen bestimmten Sachbearbeiter gesendet oder an ein automatisiertes System weitergeleitet bzw. auf ein Netzwerklaufwerk abgelegt.

Es gibt noch viele weitere Möglichkeiten, wofür Emails nützlich sein können und warum man sie automatisiert verarbeiten sollte.

Weiterlesen »

Written by Michael Kliewe

März 12th, 2010 at 9:34 am

Posted in PHP

Tagged with , ,

Cheatsheets für Entwickler

with 6 comments

Da fast jeder Entwickler das ein oder andere Cheatsheet auf seinem Schreibtisch liegen hat möchte ich hier einige gute Quellen zusammentragen. Für alle Sprachen und viele Programme sind diese Hilfsblätter verfügbar, sie hier einzeln zu verlinken wäre Wahnsinn.

Falls ein wichtiger Link fehlt, bitte ergänzen!

http://www.addedbytes.com/cheat-sheets/

http://www.cheat-sheets.org/

http://devcheatsheet.com/

http://www.petefreitag.com/item/455.cfm

http://www.tripwiremagazine.com/2009/12/60-very-useful-cheat-sheets-for-web-developers.html

http://sixrevisions.com/resources/cheat_sheets_web_developer/

http://www.webhostingsearch.com/articles/30-web-developer-cheat-sheets.php

http://www.extratuts.com/25-cheat-sheets-web-developer-should-have

Written by Michael Kliewe

März 11th, 2010 at 9:34 am

Expires-Header und Komprimierung aktivieren im Apache2

with 19 comments

Wie wir alle wissen kann man die größten Performanceverbesserungen auf der Browserseite erreichen. Ich habe bereits das Zusammenfassen von CSS- und Javascript-Dateien vorgestellt, ebenso wie das Zusammenfassen von Bildern in CSS-Sprites. Damit wird die Anzahl der Request schonmal reduziert. Aber es gibt natürlich noch mehr zu tun, beispielsweise die Requests noch weiter reduzieren durch gute Cache-Einstellungen, die wir an den Brower senden. Das werde ich hier vorstellen ebenso wie die Komprimierung mittels gzip/deflate der Dateien, die dann noch heruntergeladen werden müssen.

Cache-Einstellungen werden via HTTP-Header an den Browser mitgesendet. Zum Beispiel der Expires-Header, der angibt wie lange der Browser eine Datei cachen soll bevor er nach einer neuen Version fragt. Diese Cachedauer setzt man je nach Dateityp relativ hoch auf mehrere Tage.

Damit die unten stehenden Anweisungen vom Apache interpretiert werden können muss man das „Expires-Modul“ aktivieren, häufig kann man das wie folgt erledigen:

a2enmod expires

Hier die entsprechenden Apache-Einstellungen, die man entweder global im Apache einstellen kann, oder im entsprechenden vhost der Domain oder aber in der .htaccess-Datei speziell für Ordner:

<IfModule mod_expires.c>
    # turn on the module for this directory
    ExpiresActive on
    # set default
    ExpiresDefault "access plus 24 hours"

    # cache common graphics
    ExpiresByType image/jpg "access plus 1 months"
    ExpiresByType image/gif "access plus 1 months"
    ExpiresByType image/jpeg "access plus 1 months"
    ExpiresByType image/png "access plus 1 months"

    # cache CSS
    ExpiresByType text/css "access plus 1 months"

    # cache other filetypes
    ExpiresByType text/javascript "access plus 1 months"
    ExpiresByType application/javascript "access plus 1 months"
    ExpiresByType application/x-shockwave-flash "access plus 1 months"
</IfModule>

Mit dem Firefox-Addon Firebug kann man sich das Ergebnis anschauen:

Wie man im obigen Bild sehen kann wurde diese Datei auch gzip-komprimiert an den Browser gesendet. Dies macht vor allem Sinn bei textbasierten Dateien wie HTML, CSS, Javascript usw. Komprimierung bei bereits komprimierten Bildern wie jpg, png oder gif macht keinen Sinn, diese werden wir nicht komprimieren.

Dazu benötigen wir im Apache2 das „Modul Deflate„, und wir werden für bestimmte Dateitypen die Komprimierung aktivieren. Genau wie oben kann man die unten stehenden Anweisungen nach der Aktivierung des Moduls an die 3 bekannten Stellen setzen:

a2enmod deflate
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/x-shockwave-flash

    DeflateFilterNote Input input_info
    DeflateFilterNote Output output_info
    DeflateFilterNote Ratio ratio_info
    LogFormat '"%r" %s %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
    CustomLog /var/log/apache2/deflate_log deflate
</IfModule>

Die oberen Zeilen sollten verständlich sein, die unteren 5 Zeilen sind dazu da ein spezielles Log mit Komprimierungsinformationen anzulegen. Dieses sieht dann wie folgt aus:

"GET /wp-includes/images/smilies/icon_wink.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-content/themes/journalist/images/top.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-content/plugins/syntaxhighlighter/syntaxhighlighter/styles/shCore.css?ver=2.1.364b HTTP/1.1" 200 1917/7297 (26%)
"GET /wp-content/plugins/syntaxhighlighter/syntaxhighlighter/styles/shThemeDefault.css?ver=2.1.364b HTTP/1.1" 200 1095/3636 (30%)
"GET /wp-content/plugins/wp-cumulus/tagcloud.swf?r=5611069 HTTP/1.1" 200 34520/34610 (99%)
"GET /wp-content/plugins/wp-cumulus/tagcloud.swf?r=8457739 HTTP/1.1" 200 34520/34610 (99%)
"GET /wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/themes/advanced/link.htm?ver=327-1235-syntaxhighlighter2.3.8 HTTP/1.1" 200 974/2655 (36%)
"GET /wp-includes/js/tinymce/tiny_mce_popup.js?ver=327-1235 HTTP/1.1" 200 1921/5223 (36%)
"GET /wp-includes/js/tinymce/utils/mctabs.js?ver=327-1235 HTTP/1.1" 200 751/1786 (42%)
"GET /wp-includes/js/tinymce/utils/form_utils.js?ver=327-1235 HTTP/1.1" 200 1895/5303 (35%)
"GET /wp-includes/js/tinymce/utils/validate.js?ver=327-1235 HTTP/1.1" 200 1578/4764 (33%)
"GET /wp-includes/js/tinymce/themes/advanced/js/link.js?ver=327-1235 HTTP/1.1" 200 1467/4803 (30%)
"GET /wp-includes/js/tinymce/themes/advanced/skins/wp_theme/dialog.css?ver=327-1235-syntaxhighlighter2.3.8 HTTP/1.1" 200 1722/5510 (31%)
"GET /wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/fade-butt.png HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/tabs.gif HTTP/1.1" 200 -/- (-%)

Wie man sieht sind die Bilder nicht komprimiert worden, die CSS- und Javascript-Dateien sind teilweise auf 26% komprimiert worden. Wie man auch gut sehen kann bringt die Komprimierung der swf-Datei garnichts, man kann es also wieder deaktivieren.

Bei Änderungen an der apache2.conf bzw. den vhost-Dateien sollte man natürlich daran denken den Apache neuzustarten, damit die Änderungen aktiv werden.

In diesem Zusammenhang möchte ich auch nochmal auf die beiden sehr nützlichen Firefox-Addons Google Pagespeed und YSlow aufmerksam machen. Beide geben einen sehr guten Überblick wo Probleme liegen und was man noch verbessern kann.

Written by Michael Kliewe

März 8th, 2010 at 8:51 am