PDT 2.1 unter Windows mit Subclipse SVN Client
Meine aktuell favorisierte IDE für PHP ist eclipse. Eclipse ist eine vielfach nutzbare IDE, die ursprünglich für Java gedacht ist, aber auch andere Sprachen wie PHP, C, C++ und einige weitere unterstützt. Zend höchstselbst entwickelt die „PHP Development Tools“, auch PDT genannt, was im Prinzip ein eclipse inclusive aller nötigen PHP-Module plus den Zend-Local-Debugger ist.
PDT ist seit kurzem in Version 3.5 verfügbar, Codename Galileo. Zum Download steht es bei Zend: http://www.zend.com/de/community/pdt . PDT ist heute die erste und einzige IDE, die PHP 5.3 unterstützt, die anderen IDEs (mehr dazu am Schluss) werden aber sicher bald nachziehen.
Die Installation ist denkbar einfach: zip herunterladen und entpacken, danach die eclipse.exe starten und man kann loslegen. Da ich jedoch meinen Code im SVN liegen habe, muß ich als erstes noch einen SVN-Client installieren. Zur Auswahl gibt es aktuell Subclipse und Subversive. Ich bevorzuge Subclipse, es lief bisher ohne Probleme. Via Google kann man dazu jede Menge Vergleiche finden, das möchte ich hier nicht breittreten, da könnt ihr euch selbst informieren: „Subversion vs Subclipse“ @ Google
Die Installation ist schnell gemacht:
Dann die Subclipse-Site hinzufügen (Links gibt es auf der Subclipse Seite):
Dann kann man aus den verfügbaren Paketen das Subclipse auswählen:
Details nochmal bestätigen:
Dann noch einen Neustart von eclipse, fertig! Dann kann man links mit Hilfe der Import-Funktion ein Projekt aus dem SVN auschecken.
Nicht unerwähnt bleiben soll jedoch, dass es natürlich gute alternative PHP IDEs gibt, wie zum Beispiel Netbeans oder das kostenpflichtige Zend Studio for eclipse. In der Firma sind wir aktuell gespalten, einige sind umgestiegen auf Netbeans, ich jedoch bleibe vorerst beim PDT, da es bisher NIE Probleme machte (außer man updated eine lokale Kopie mit dem TortoiseSVN Client, dann kann eclipse diese lokale Kopie nicht mehr öffnen, also entweder den eclipse-internen SVN-Client ODER TortoiseSVN nutzen, aber das ist eine andere Geschichte)
PHP 5.3 released!
Closures, Late Static Binding, Namespaces, neuer Mysql Native Driver, Garbage Collection und und und.
Wem das (noch) nichts sagt, sollte sich in den nächsten Tagen und Wochen damit beschäftigen (hier im Blog werde ich sicherlich auch einiges davon vorstellen), denn
PHP 5.3
wurde soeben offiziell released! http://www.php.net/downloads.php
Ich persönlich würde damit zwar noch nicht auf Produktiv-Systeme gehen, aber zuhause in Entwicklungsumgebungen und vielleicht auf kleinen Homepages kann man damit schon arbeiten denke ich. Wenn in 4-6 Wochen dann die ersten Bugfixes verfügbar sind, werden wir in der Firma sicher auch mal intensiver damit testen, um unsere alten Systeme auf kurz oder lang umzustellen. Das ist aber häufig ein monatelanger Prozess, wir werden sehen.
Da dies kein langer Post werden soll, kann ich nur sagen: Probiert es aus und testet die neuen Funktionen!
Firewall Beschränkungen prüfen
Zuhause hat man diese Probleme wohl nicht so sehr, und auch auf einem Rootserver braucht man sich nur sehr selten damit rumplagen: Firewalls, die den Zugriff auf andere Systeme blocken.
Firewalls sind im Prinzip nichts anderes als Programme (oder Hardware), die im Netzwerk oder auf einem System installiert sind und Netzwerkpakete (nicht nur TCP/IP, sondern auch UDP, ICMP Pakete usw) untersuchen kann. Jede Firewall hat Regeln, die beschreiben, was passieren soll wenn bestimmte Pakete ankommen. Zum Beispiel kann sie die Verbindung komplett unterbinden (d.h. die ankommenden Pakete droppen) wenn ein Quellsystem 1.2.3.4 das Zielsystem 6.7.8.9 auf Port 25 versucht zu erreichen. Das wäre ein Blacklist-Eintrag.
Sicherer und häufig einfacher ist aber eine Whitelist. Dann wird prinzipiell erstmal alles gedroppt, und nur einige definierte Verbindungen dürfen durchgelassen werden. Bei einer lokalen Firewall zuhause oder auf einem Server resultiert das in 1-20 Regeln. In einer größeren Firma mit komplexen Netzwerken, vielen vielen Servern und Arbeitsrechnern, einigen dutzend IP-Bereichen und Hardware-Firewalls, die ganze Netze voneinander trennen (also nicht hunderte lokal installierte Software-Firewalls), artet diese Sicherheit häufig auch in viel Arbeit und komplexe Regeln aus.
Kürzlich mußten wir ein System mit einer komplexen Software, welche Verbindungen zu aktuell 65 anderen Systemen (es werden kontinuierlich mehr) aufbaut, um dort Daten abzuholen und abzuliefern, von einem Server auf einen anderen Server in einem anderen Netz umziehen. Da wir keine Listen hatten, zu welchen Zielsystemen eine Verbindung möglich ist und zu welchen nicht, hilft nur ausprobieren.
Da wir Informatiker ja bekanntlich faul sind (was nicht immer schlecht ist, denn faule Programmierer meiden redundanten Code, programmieren selten mehr Schnick-Schnack in eine Anwendung als benötigt usw) haben wir uns ein kleines Script geschrieben, das alle benötigten Zielsysteme durchprobiert und eine schöne Liste der nicht erfolgreichen Verbindungen ausgibt.
Unsere erste Version tat genau das: Es versucht, alle Zielsysteme auf einem bestimmten Port zu erreichen, indem es eine Socketverbindung aufbaut und dann wieder trennt. Ein schicker 40-Zeiler:
<?php require_once('../init.php'); $configIni = Zend_Registry::get($configIni); echo 'We are using database: ' . DATABASE_DBNAME."\n\n"; $portChecks = array(); $portChecks[] = array('Host' => $configIni->mail->standard->host, 'Port' => $configIni->mail->standard->port); $portChecks[] = array('Host' => $configIni->mail->secure->host, 'Port' => $configIni->mail->secure->port); $portChecks[] = array('Host' => $configIni->db->config->hostnameonly, 'Port' => $configIni->db->config->port); $portChecks[] = array('Host' => $configIni->product1->host, 'Port' => $configIni->product1->port); $db = MDB2::singleton('mssql://' . DATABASE_USER . ':' . DATABASE_PASS . '@' . DATABASE_SERVER . ':' . DATABASE_PORT . '/' . DATABASE_DBNAME); $db->setFetchMode(MDB2_FETCHMODE_ASSOC); // add FTP Checks from DB $ftpModules = $db->queryAll('SELECT DISTINCT Server, Serverport FROM FTP'); foreach ($ftpModules as $ftpModule) { $portChecks[] = array('Host' => $ftpModule['server'], 'Port' => $ftpModule['serverport'] == 0 ? 21 : $ftpModule['serverport'] ); } // add SFTP Checks from DB $sftpModules = $db->queryAll('SELECT DISTINCT Server, Serverport FROM SFTP'); foreach ($sftpModules as $sftpModule) { $portChecks[] = array('Host' => $sftpModule['server'], 'Port' => $sftpModule['serverport'] == 0 ? 22 : $sftpModule['serverport'] ); } echo "\nStarting Port Tests:\n"; foreach ($portChecks as $portCheck) { $ret = @fsockopen($portCheck['Host'], $portCheck['Port']); if (!$ret) { echo 'Port ' . $portCheck['Port'] . ' on Host ' . $portCheck['Host'] . " (IP: ".gethostbyname($portCheck['Host']).") cannot be opened. Please check!\n"; } else { fclose($ret); echo "."; } }
In der zweiten Version kann es aktuell auch noch etwas detaillierter die eigentlichen Protokolle nutzen und sich zB auf einem FTP-Server einloggen oder SMB-Pfade prüfen. Das geht über den eigentlichen Porttest hinaus, ist aber für unsere Einsatzzwecke durchaus interessant, um zB falsche Login-Informationen oder anderweitige Probleme aufzudecken.
Erste Twitter Tests
Da Twitter in aller Munde ist, habe ich es mir am Wochenende nun auch mal angeschaut und mir einen Account eingerichtet. Zwar schon die letzten Monate des öfteres gehört und gelesen, konnte ich mich bisher nicht davon überzeugen lassen. Da auch keiner meiner Bekannten twittert, war der Anreiz nicht wirklich groß.
Jetzt am Wochenende habe ich einen Podcast vom Chaos Computer Club: Chaosradio Folge 147 gehört, der mich nun zu Experimenten angespornt hat.
Ein Account ist schnell erstellt, eine Statusnachricht geschrieben, und ein paar Leuten folge ich auch bereits.
Heute habe ich mir das WordPress-Plugin TwitterSuite installiert, mit dem ich hoffe, automatische Tweets zu senden bei neuen Beiträgen, Last Tweets anzuzeigen und einigem mehr. Dieser Post ist auch dazu da, diese Funktionalität mal zu testen. Ich hoffe, dass es funktioniert 😉
EDIT: Hmm, das ging wohl voll in die Hose. Habe wohl curl nicht installiert auf dem Server. *verschnauf* Hätte ja auch so einfach sein können.
Da ich jetzt weder Zeit noch Lust habe, probiere ich nun den twitter_updater.
EDIT2: Scheint zu funktionieren! *jubel*
Thumbnails erstellen mit PHP
Da es im Zend Framework keine schöne Klasse für diese Aufgabe gibt (Zend_Image gab es mal als Proposal, wurde aber abgelehnt), muss man anderweitig eine Lösung finden.
Ich habe dazu eine uralte Funktion, die aber nach wie vor fabelhaft funktioniert. Man übergibt einfach nur den Pfad zur Quelldatei (häufig ist das eine hochgeladene Datei, es kann sowohl ein jpg als auch ein gif sein), ein Zielverzeichnis (häufig ein Ordner im webroot), sowie Informationen über die Zieldatei: Dateiname, Endung, maximale Höhe und Breite.
Ein Beispiel würde so aussehen:
Util::createThumbnailAndSave($_FILES['uploadfile']['tmp_name'], 'images/uploads', $_FILES['uploadfile']['name'], 'jpg', 250, 250)
Danach schreibt man die Informationen über die Datei natürlich noch in eine Datenbank, damit man sie auf der Webseite einbinden kann.
Und natürlich möchte ich euch meine kleine Funktion nicht vorenthalten. Es wird kein Imagick benötigt, sondern nur eine „normale“ PHP-Installation incl. aktivierten GD-Funktionen.
public static function createThumbnailAndSave($filePath, $targetDir, $targetFilename, $targetExtension, $targetWidth, $targetHeight) { $imageinfo = getimagesize($filePath); // check if source image is smaller than target dimensions if ($imageinfo[0] > $targetWidth || $imageinfo[1] > $targetHeight) { if ($imageinfo[2] == 1) { // GIF $srcImg = imagecreatefromgif($filePath); } elseif ($imageinfo[2] == 2) { // JPG $srcImg = imagecreatefromjpeg($filePath); } $widthDivisor = $imageinfo[0] / $targetWidth; $heightDivisor = $imageinfo[1] / $targetHeight; if ($widthDivisor > $heightDivisor) { $dstImg = imagecreatetruecolor($targetWidth, $imageinfo[1] / $widthDivisor); } else { $dstImg = imagecreatetruecolor($imageinfo[0] / $heightDivisor, $targetHeight); } imagecopyresampled($dstImg, $srcImg, 0, 0, 0, 0, imagesx($dstImg), imagesy($dstImg), imagesx($srcImg), imagesy($srcImg)); // Save to harddisc and delete from RAM imagejpeg($dstImg, $targetDir . "/" . $targetFilename . "." . $targetExtension, 95); $fsize = filesize($targetDir . "/" . $targetFilename . "." . $targetExtension); if ($fsize > 50000) { imagejpeg($dstImg, $targetDir . "/" . $targetFilename . "." . $targetExtension, 60); } imagedestroy($dstImg); imagedestroy($srcImg); } else { copy($filePath, $targetDir . "/" . $targetFilename . "." . $targetExtension); } chmod($targetDir . "/" . $targetFilename . "." . $targetExtension, 0777); }
Eigentlich könnte ich sie mal auf Aktualität überprüfen, heutzutage würde ich sie wahrscheinlich auch etwas anders schreiben. Aber für meine paar kleinen privaten Homepages reicht es. Alternativen sind natürlich fertige Klassen von phpclasses.org etc,