Archiv für die Kategorie ‘PHP und MySQL’

Erstellen einer Facebook-Applikation

Samstag, 27. November 2010

Wie üblich, wenn ich einem Tutorial folge, um eine Facebook-Applikation zu erstellen, erhalte ich nicht (sofort) das vom Tutorialverfasser dargestellte Ergebnis, sondern in der Regel Fehlermeldungen an verschiedenen Stellen. Offenbar gibt es zu viele verschiedene Einstellungen und Serverkonfigurationen, um ein einziges Skript überall gleich lauffähig zu bekommen. *seufz*

In diesem Fall folgte ich Emanuele Feronatos Tutorial “Create a Facebook application like “Friend interview” und stieß nach Auruf meiner index.php im Browser auf die folgende Fehlermeldung:

Parse error: parse error in /mnt/web9/52/01/5163301/htdocs/hella/facebook.php on line 4

Fatal error: Cannot instantiate non-existent class: facebook in /mnt/web9/52/01/5163301/htdocs/hella/index.php on line 5

In den Kommentaren unter Emanueles Artikel riet jemand, die Dateiendung manuell in “php5″ umzubenennen.
Nachdem ich jetzt also keine index.php, sondern eine index.php5 auf meinem Testserver liegen hatte und diese aufrief, klappte dieser Teil schon mal.

Jedoch blieb die Applikation dann wieder mit einer Fehlermeldung hängen; diesmal stammte sie von Facebook und warnte mich durch Ausgabe des Fehlercodes “API Error Code: 191″, dass die angegebene URL nicht der Applikation gehöre — WTF?
Es hat einige Zeit gekostet, herauszufinden, wie ich diesen Eisberg umschiffen kann, aber die Lösung ist glücklicherweise einfach.
Emanuele übersah es in seinem Tutorial, darauf hinzuweisen, dass unter “Edit Settings” im Facebook Developer Bereich auch unter “Web Site” Einstellungen vorgenommen werden müssen. Vielleicht klappt es bei ihm ja auch ohne, bei mir allerdings ging es mit der Applikation erst weiter, nachdem ich folgendes eingetragen hatte:

Nach diesem Schritt lief die Applikation immerhin bis zur Anzeige des Autorisierungsdialogs. Der Moment der Erleichterung währte nicht allzu lang, denn direkt anschließend bockte PHP erneut:

Fatal error: Uncaught CurlException: 60: SSL certificate problem, verify that the CA cert is OK. Details: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed thrown in /mnt/web9/52/01/5163301/htdocs/hella/facebook.php on line 612

Dieses Problem scheint der Netzgemeinde bekannt zu sein. An verschiedenen (so auch hier) Stellen wird geraten, die Datei facebook.php geringfügig zu manipulieren, um das Problem zu beheben. In meinem Fall hat es gereicht, eine Zeile Code in facebook.php einzufügen (im folgenden Skript mit !!! markiert):

/**
* Makes an HTTP request. This method can be overriden by subclasses if
* developers want to do fancier things or use something other than curl to
* make the request.
*
* @param String $url the URL to make the request to
* @param Array $params the parameters to use for the POST body
* @param CurlHandler $ch optional initialized curl handle
* @return String the response text
*/
protected function makeRequest($url, $params, $ch=null) {
if (!$ch) {
$ch = curl_init();
}

$opts = self::$CURL_OPTS;
if ($this->useFileUploadSupport()) {
$opts[CURLOPT_POSTFIELDS] = $params;
} else {
$opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
}
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_SSL_VERIFYPEER] = false; // !!!

// disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
// for 2 seconds if the server does not support this header.
if (isset($opts[CURLOPT_HTTPHEADER])) {
$existing_headers = $opts[CURLOPT_HTTPHEADER];
$existing_headers[] = 'Expect:';
$opts[CURLOPT_HTTPHEADER] = $existing_headers;
} else {
$opts[CURLOPT_HTTPHEADER] = array('Expect:');
}

curl_setopt_array($ch, $opts);
$result = curl_exec($ch);
if ($result === false) {
$e = new FacebookApiException(array(
'error_code' => curl_errno($ch),
'error' => array(
'message' => curl_error($ch),
'type' => 'CurlException',
),
));
curl_close($ch);
throw $e;
}
curl_close($ch);
return $result;
}

Per GD-Library generiertes JPG lässt sich nicht herunterladen

Mittwoch, 24. März 2010

Über die Verwendung der GD-Library zur Bildmanipulation gibt es ja reichlich Quellen im Internet zu finden. Dass allerdings per PHP an den Browser gesendete Bilder in bestimmten Szenarien nicht herunterladbar sein können, wird eher selten erwähnt. Eine Lösung dafür findet sich entsprechend ähnlich schwierig.
In meinem Fall hatte ich es mit einer PHP-Datei zu tun, der per POST ein Dateipfad zu einem JPG übergeben wurde, das per GD-Library-Funktionen mit einem Wasserzeichen verziert werden sollte. Das PHP-Skript wurde aus Flash aufgerufen.
Als Ergebnis eines Skriptaufrufs erhielt ich brav das JPG in einem neuen Browserfenster. Jedoch der Versuch, das Bild via Rechtsklick und “Speichern unter…” auf die Festplatte zu speichern, scheiterte. Im Speichern-Dialog war auch der Name meines PHP-Skripts als Name der zu speichernden Datei voreingetragen, nicht etwa der des JPGs.

So ähnlich sah mein Skript bis zu jenem Zeitpunkt aus (hier gekürzt):
header('Content-Type: image/jpeg');
$original_pic = 'pics/coolpicture.jpg';
$watermark = imagecreatefrompng('watermark.png');
$watermark_width = imagesx($watermark);
$watermark_height = imagesy($watermark);
$image = imagecreatetruecolor($watermark_width, $watermark_height);
$image = imagecreatefromjpeg($original_pic);
$size = getimagesize($original_pic);
$dest_x = $size[0] - $watermark_width - 10;
$dest_y = 10; // $size[1] - $watermark_height - 5;
imagecopymerge($image, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height, 80);
imagejpeg($image);
imagedestroy($image);
imagedestroy($watermark);
?>

Durch Einfügen folgender Zeilen erhielt ich statt eines neuen Browserfensters einen “Datei herunterladen”-Dialog, der dann immerhin die Datei unter einem festen Namen speicherbar machte:
header('Content-Disposition: attachment; filename=festerName.jpg');

Verzeichnisschutz mit .htaccess und .htpasswd

Mittwoch, 17. März 2010

Mit beispielsweise diesem Generator eine einfache Sache, wenn man weiß, wie der “interne Pfad zum Verzeichnis auf dem Server” lautet. Den bekommt man aber ebenfalls leicht zu fassen mit einem PHP-Schnipsel:
echo "Document root: ".$_SERVER["DOCUMENT_ROOT"];
phpinfo();
?>

Normalerweise sollte phpinfo() bereits alles Nötige liefern. Unter “Environment” findet sich der Eintrag “DOCUMENT_ROOT” und daneben dann das Gesuchte. Zeile 2 stellt eine Alternative dar.

Geocoding mit PHP und dem Google Maps API

Dienstag, 30. Juni 2009

Schöner Artikel zum Thema Geocoding mit PHP in Verbindung mit dem Google Maps API. Mit Downloadmöglichkeit für die besprochenen Listings.

Die im Artikel geschilderte Klasse Geocoder.php macht allerdings PHP5 und cURL-Support erforderlich.

Ordnerzugriff beschränken auf 1blu-Server

Mittwoch, 04. Juli 2007

Da man bei 1blu offenbar darauf verzichtet, KundInnen eine praktische Funktion anzubieten, mittels derer auf einfache Weise ein Verzeichnis mit einem Zugangsschutz versehen werden kann, ist Handarbeit gefragt.

Statt der mir geläufigen Kombination aus .htaccess und .htpasswd muss es hier das Paar .htaccess und .htuser sein. Letztgenannte sieht aber genau so aus wie die bekannte .htpasswd, heißt aber eben nur anders.

Wird beides im ASCII-Modus hochgeladen, klappt auch alles. Aber nur, wenn man sich vorher den absoluten Pfad aus den FAQ herausgepuhlt hat. Der sah bei der aktuellen Kundin so aus: /hp/ag/ae/rd/www/

An diesen Pfad schließt sich dann noch der Rest des Pfades an, der auf die .htuser-Datei zeigt, etwa so: /hp/ag/ae/rd/www/meinGeschuetztesVerzeichnis/

Somit könnte eine schlichte .htaccess-Datei so aussehen:

AuthName “Geschuetzter Bereich”
AuthType Basic
AuthUserFile /hp/ag/ae/rd/www/meinGeschuetztesVerzeichnis/.htuser
AuthGroupFile /dev/null
require valid-user

Beide Dateien, also .htaccess und .htuser, liegen dann im Verzeichnis namens meinGeschuetztesVerzeichnis.

Geodating für den Hausgebrauch

Dienstag, 24. April 2007

Ein Kunde wollte gern für seine eigenen GoogleMaps ein CMS haben, bei dem er nur eine Adresse, wie z.B. “Grindelallee 27c, 20146 Hamburg”, eingeben muss und per Knopfdruck die nötigen Breiten- und Längengraddaten erhält.

Kann ja nicht so schwer sein, dachte ich. Nach ein paar Stunden Recherche und Bastelei habe ich dann auch eine Lösung programmiert, die ohne lästiges GoogleMaps-API-Einbinden auskommt.

Die Demo gibt die zwei Werte Latitude und Longitude lediglich in einem JavaScript-Fenster aus. Im CMS für meinen Kunden hingegen werden gleich diverse Formularfelder (Straße, Hausnummer, Postleitzahl, Stadt, Breiten- und Längengrad) vorausgefüllt, so dass er eine Menge Arbeit einspart.

Die vollständige GoogleMaps-Seite mit allen so eingetragenen Adressen zu generieren, dürfte jetzt nur noch Formsache sein.

Mein Newsgroup-Kollege Dominik machte mich noch auf dieses Projekt (OpenGeoDB – freie Geokoordinaten-Datenbank) aufmerksam. Sicher auch mehr als einen flüchtigen Blick wert.

CMS-Programmierung: De-/Aktivierung einzelner Seiten

Donnerstag, 22. Februar 2007

Man ersetze “MP” durch “Menüpunkt” und “UP” durch “Untermenüpunkt(e/en)”:

Wenn ein MP ohne eigene UP oder ein einzelner UP unsichtbar geschaltet werden soll, ist das kein Problem.
Soll aber ein MP unsichtbar werden, der UP hat, müssen alle UP mit unsichtbar werden und gesperrt bleiben (keine Wieder-Sichtbarmachung möglich), solange der übergeordnete MP nicht (wieder) sichtbar ist.
Wird ein unsichtbarer MP mit UP wieder sichtbar, bleiben dennoch alle UP erst einmal unsichtbar, sind dann aber entsperrt und können sichtbar gemacht werden.

Alles klar? ;-)

Freizeilen von PHP nach Flash

Donnerstag, 25. Januar 2007

Vor einiger Zeit schrieb ich ja bereits über die Tücken der Sonderzeichen und Freizeilen in Bezug auf PHP und Flash (wer der große Schuldige ist, kann ich gar nicht recht sagen). Wenn ich den Artikel lese, erhalte ich am Schluss den Eindruck, dass ich die Probleme ein für allemal gemeistert hätte. Wie ich heute morgen herausfinden musste, befand ich mich mit dieser Annahme auf der nicht-metallischen Straße oder auch dem hölzernen Pfad…
Bei einem aktuellen Projekt werden Daten in HTML-Formularfelder eingegeben, per PHP in einer MySQL-Datenbank abgelegt und später von einem Flashfrontend angefordert. Dazu führt Flash eine PHP-Datei aus, die die Daten aus der Datenbank abholt und per echo-Befehl an Flash liefert. Im Grunde dasselbe Szenario wie Anno 2005. Doch im Gegensatz zu damals spielt es im vorliegenden Fall offenbar keine Rolle, dass ich die Daten (wie damals) per PHP-Skript in die Datenbank einspeise, denn aus einem Testeintrag…

Eine Zeile frei:

Zwei Zeilen frei:

Ende.

…wird in Flash 8…

Eine Zeile frei:
Zwei Zeilen frei:

Ende.

Wo eigentlich eine Zeile frei sein sollte, werden in Flash derer zwei angezeigt. Noch größer klafft die Lücke bei zwei gewünschten Freizeilen.

Warum ich seinerzeit ohne Skript-Manipulationen weitergekommen bin, ist mir heute schleierhaft. Aber ich habe eine Lösung gefunden, die hoffentlich auch beim nächsten Projekt noch funktioniert…:

Statt die Textdaten unverändert aus der Datenbank an Flash zu übergeben mit…

$send2flash = “copy=”.utf8_encode( $row['copy'] ).”&”;

…lasse ich per str_replace erst alle Vorkommen der Steuerzeichen #0D #0A oder Dezimal 13 10 — Erstgenanntes steht für Carriage Return, Letzteres für Line feed — durch ein einfaches \n ersetzen:

$transformedCopy = str_replace( “\r\n”, “\n”, $row['copy'] );
$send2flash = “copy=”.utf8_encode( $transformedCopy ).”&”;

Dann klappt es. Diesmal.

UTF-8-Codierung verhindert Senden eines HTTP-Header

Mittwoch, 26. Juli 2006

Randnotiz für den Fall, dass ich zukünftig nicht wieder Stunden Zeit brauchen möchte, um festzustellen, dass die Konvertierung eines PHP-Dokumentes von ASCII nach UTF-8 (UltraEdit) keine gute Idee ist, wenn das PHP-Dokument einen HTTP-Header senden möchte. Ergebnis wäre die berüchtigte Header-already-sent-Fehlermeldung.

Zeit(punkt) in DB speichern

Mittwoch, 26. Juli 2006

Bevor ich’s wieder vergesse, notiere ich’s mir gerade mal.
Beim Speichern eines Datums im Timestamp-Format funktioniert Folgendes ganz gut:

  • In der DB-Tabelle ein Feld als INT anlegen
  • Im PHP-Skript per $zeitjetzt = time(); den Timestamp schnappen

Der Timestamp liegt in Sekunden vor, d.h. 1090845461 und 1090845521 liegen genau 1 Minute auseinander.