Month: November 2008

PHP Stylesheet CSS

Wie bereits in den 5 Tipps für eine schnellere Webseite beschrieben sollte man soviel Code wie möglich in die CSS Datei auslagern. CSS Dateien haben, genauso wie HTML nur einen Nachteil, man kann keine Logik implementieren. In PHP ist dies jedoch möglich. Außerdem kann PHP so tun als sei es CSS.

[php]

[/php]

In HTML wird es wie eine CSS Datei eingebunden.

[html] [/html]

Manche Kunden möchten gerne das jede Kategorie eine andere Farbe hat. Bevor man jetzt anfängt 10 verschiedene Stylesheet Dateien anzulegen, wäre es einfacher jedes Design in ein anderen Ordner zu legen und diesen per GET zu übergeben.

[html] [/html]

Um das Stylesheet übersichtlich zu gestalten, sollte man wirklich nur den Dynamischen Teil in eine PHP CSS Datei auslagern. Die untere CSS Datei würde wie folgt aussehen:

[css]

/* NUR FUER FARBEN UND HINTERGRUENDE */
/* DER REST ALLES IN STYLESHEET.CSS */

/* KOPF */

#kopf {
background-image:url(kopf/header_start.jpg);
background-repeat:no-repeat;
height: 220px;
}
[/css]

In der Codevorschau ist dieses Beispiel sehr bunt. Wer jedoch solche Dateien mit VI bzw. VIM erstellt, wird jedoch enttäuscht werden, weil der Editor das Syntaxhighliting aufgrund der Dateiendung entscheidet. Dies kann man jedoch manuell auf CSS umschalten. Danach ist der PHP Code zwar schwarz, aber die Datei sollte auch hauptsächlich aus CSS bestehen.

Wer in seinem VIM-Menü verzweifelt nach CSS sucht, wird unter Cascading Style Sheets fündig.

Meinung – Fazit zu 1blu

Während der langen Blogpause bin ich mindestens zweimal umgezogen. Beim durchforsten des Blogs ist mir aufgefallen wie euphorisch ich damals noch über 1blu schrieb. Heute würde ich dies nicht mehr sagen. Das Sprichwort “Wer billig kauft, kauft zweimal” hat sich mal wieder bewahrheitet.

Folgende Punkte haben mich zum Umzug bewogen:
– Samstag / Sonntag war der Server und die Verbindung extrem langsam
– Der Support hat auf E-Mails nicht geantwortet
– Die Bedienung von Plesk und Virtuozzo war sehr verwirrend
– Plesk hatte ein Eigenleben*

Nach einem kleinen Umweg über netclusive bin ich schließlich bei Hetzner gelandet, auf einem Root Server. Diesen einzurichten und zu konfigurieren, erfordert jedoch ein fundiertes Linux-Wissen und Erfahrung mit Servern die im Internet stehen.

Im Gegensatz zu 1blu läuft auf dem Hetznerserver kein Mailserver. Für eingetragene Domains und Mailadressen werden Mails angenommen und weitergeleitet oder abgelehnt. Es gibt jedoch keine Mailbox auf dem System. Die Aussortierung von Spam erfordert einfach zu viele Ressourcen und die Speicherung von Mails ist ein Faß ohne Boden, bei Bekannten, die immer nur 1 MB mehr haben wollen.

* Das Eigenleben äußerte sich darin, das sich Dienste nicht abschalten ließen oder abgeschaltete Dienste weiterhin Mails schickten.

Spamschutz: Mathetest

Nachdem mittlerweile die schlechten Captchas geknackt wurden, hat man sich neue Spamschutzmechanismen einfallen gelassen. Dazu zählen unter anderem Hunde in Katzenbilder oder umgekehrt erkennen bzw. eingescannten Text abtippen, um so zu helfen Bücher zu digitalisieren.

Captchas, Hunde, Katzen und eingescannter Text hat ein Nachteil: es sind immer Bilder. Dies wurde am Anfang als der Vorteil gefeiert, weil nur Menschen Bilder lesen und verstehen können. Mittlerweile ist man schlauer und Captchas die ihren Text nicht bis zur Unkenntlichkeit verschleiern, können mittels OCR automatisiert ausgelesen werden. Außerdem sind Bilder ein großer Nachteil für Braille Browser.

Zahlen die direkt im Quellcode stehen können von Braille Browsern natürlich wesentlich verständlicher interpretiert werden, aber dies sollten die Spamrobots doch auch können. Als vermute ich mal wird Anfangs das Spamaufkommen, aufgrund der Neuheit, sicherlich nachlassen, aber im Endeffekt verpufft diese Maßnahme und nach kurzer Zeit hat man wieder ein Spamaufkommen wie zuvor.

Bevor ich meinen WordPress Blog auf Akismet umstellte, hatte ich auch massive Probleme mit Spam. Dies konnte ich kurzfristig durch den Einsatzes eines Plugins senken, welches bei zuvielen Links ein erneutes Absenden forderte, jedoch verpuffte diese Wirkung bald.

Traue keiner Statistik: Kein Google Analytics und Blogcounter in der Preview

Bevor man seinen Post veröffentlicht, sollte man ihn vorher nochmals durchlesen. Dazu gibt es in WordPress den “Preview this Post” Button. Diesen Button benutze ich recht häufig, weil ich auch oft sehen will, wie der Quellcode aussieht oder weil mir immer wieder Sachen auf- und einfallen, die ich dringend noch ändern muß.

Zu meiner Schande muß ich gestehen, habe ich kein Plugin benutzt um den Google Analytics Code bzw. den Blogcounter Code in das Template einzubinden. Sondern ich habe es direkt in die header.php und footer.php eingetragen.

Die header.php und footer.php werden jedoch auch jedes mal in der Preview geladen, wodurch natürlich auch jedesmal der Google Analytics Code und der Blogcounter aufgerufen werden. Nachdem ich gestern nachschauen wollte, ob sich an meinen Besucherzahlen etwas geändert hatte, mußte ich feststellen, das die Unique Visitors gleich geblieben sind. Die Page Impressions sind jedoch gestiegen.

Vor allem bei Beiträgen die bisher noch nicht veröffentlicht wurden, waren die Page Impressions hoch. Also kurz gerechnet. Wenn ich mir einen Beitrag durchschnittlich 5 Mal vorher anschaue, er im Monat aber insgesamt nur 100 mal aufgerufen wird, habe ich schon eine Unschärfe von 5% drin. Das ist mehr als die derzeitige Inflation.

Also schnell noch mal in den Code gegangen und folgende Zeile eingefügt

[php]
if(!isset($_GET[‘preview’])){
[/php]

bzw. natürlich muß nach dem Google Analytics und Blogcounter die Klammer auch wieder geschlossen werden

[php]
}
[/php]

Bin mir nicht sicher, ob die zwei Extensions, die es im Internet dazu gibt, dies auch gemacht hätten. Also im Preview Modus den Code ausgeblendet. Wollte die Extensions vorhin ausprobieren, jedoch ging der Download nicht. Wäre vielleicht mal eine gute Gelegenheit, selber eine Extension zu veröffentlichen. Alternativ könnte man auch sagen, sobald jemand am Backend eingeloggt ist, wird der Statistik Code nicht mehr eingebunden.

Java Tutorial: Hibernate, MySQL, Annotations

Heute Morgen das Beispiel mit XML veröffentlicht, folgt jetzt das gleiche Beispiel mit Annotations. Diese sind erst seit Java 5 verfügbar und bieten den Vorteil man muss nicht immer zwei Dateien anpassen. Mit Annotations ist es möglich direkt im Java Code festzulegen wie das Objekt später in der Datenbank abgelegt wird.

Bereits in der Übersicht kann man sehen, das die Konfigurationsdatei für das Objekt wegfällt. Die Konfiguration die vorher in der der XML Datei vorgenommen wurde wird jetzt direkt in die Java Klasse implementiert. Natürlich entfällt dann auch die Angabe über die Konfigurationsdatei in der Hibernate Konfiguration.
Aber genug Geschwätz sehen wir uns das Objekt an:

[java]
// File: Tisch.java

package obj;

import java.io.Serializable;
import java.text.MessageFormat;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;

@Entity
public class Tisch implements Serializable{

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@SequenceGenerator(name = “tisch_gen”, sequenceName = “tisch_id_seq”)
private Integer id;
private Integer Fuesse;
private String Material;

public Tisch(){ }

private Integer getId() {
return id;
}

private void setId(Integer id) {
this.id = id;
}

public Integer getFuesse() {
return Fuesse;
}

public void setFuesse(Integer fuesse) {
Fuesse = fuesse;
}

public String getMaterial() {
return Material;
}

public void setMaterial(String material) {
this.Material = material;
}

public String toString() {
return MessageFormat.format(“{0}: Fuesse={1}, Material={2}”, new Object[] {
getClass().getSimpleName(), Fuesse, Material });
}
}
[/java]

Wie oben bereits oft erwähnt entfällt die Konfigurationsdatei. Also kommen wir gleich zu der Session.

[java]
// File: SingSessionFactory.java

package hibe;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

public class SingSessionFactory {

/** The single instance of hibernate SessionFactory */
private static org.hibernate.SessionFactory sessionFactory;

/**
* Default constructor. It is private to guaranty singleton
*/
private SingSessionFactory() {
}

static {
final AnnotationConfiguration cfg = new AnnotationConfiguration();
cfg.configure(“/hibernate.cfg.xml”);
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getInstance() {
return sessionFactory;
}

}
[/java]

Die Main Klasse

[java]
// File: HibeMySQL.java

package exa;

import hibe.SingSessionFactory;
import org.apache.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.Transaction;

import obj.Tisch;

public class HibeMySQL {

private static Logger log = Logger.getLogger(HibeMySQL.class);

public static void main(String[] args) {
Tisch wohnzimmer = new Tisch();
wohnzimmer.setMaterial(“Eiche”);
wohnzimmer.setFuesse(3);

Session ses = SingSessionFactory.getInstance().getCurrentSession();
Transaction tx = ses.beginTransaction();

ses.save(wohnzimmer);

tx.commit();
}
}
[/java]

Die angepasste Konfiguration von Hibernate

[xml]



jdbc:mysql://localhost:3306/bank root com.mysql.jdbc.Driver org.hibernate.dialect.MySQLDialect org.hibernate.transaction.JDBCTransactionFactory thread true

true update


[/xml]

Zur Vollständigkeit noch die Konfigurationsdatei von Log4J.

[xml]
# File: log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L – %m%n

### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L – %m%n

### set log levels – for more verbose logging change ‘info’ to ‘debug’ ###

log4j.rootLogger=debug, stdout

log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug

### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug

### log just the SQL
log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug

### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=info

### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug

### log cache activity ###
log4j.logger.org.hibernate.cache=info

### log transaction activity
#log4j.logger.org.hibernate.transaction=debug

### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug

### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
[/xml]