Git für Windows installieren und SSH Keys nutzen

Ich benutze für die Installation die Aktuelle Preview Version von msysgit (Git-1.8.3-preview20130601.exe).

Da ich nur die Kommandozeilen Komponenten benötige, habe ich die „Windows Explorer integration“ abgewählt.

Setup1
Setup2

Hier verwende ich extra „Run Git and included Unix tools form Windows Command Promt“, damit ich Git in der Kommandozeile laufen lassen kann ohne den Pfad der Git Datei angeben zu müssen. Außerdem ist das der einzige Punkt, bei dem dann die SSH Authentifizierung vernünftig funktioniert.

Setup3

Ich benutze das von Git mitgelieferte OpenSSH.

Wir verwenden immer die „Unix-style line endings“. Dies kann man aber auch projektweise mit Hilfe einer .gitattributes definieren.

Setup4

Danach wird Git installiert und man kann es in der Windows cmd nutzen. Ich nutze es direkt in der IDE PHPStorm.

Um Git jetzt noch mit SSH Zertifikaten laufen zu lassen, müssen wir nur noch der Anleitung folgen, die ich hier nochmal kurz durchgehe.

Punkt 1: Überprüfen, ob schon SSH Keys exisitieren. Diese sollten unter C:\Users\<Benutzername>\.ssh zu finden sein und im Normalfall id_rsa und id_rsa.pub heißen.

Wenn schon welche existieren, kann Punkt 2 übersprungen werden.

Punkt 2: SSH Key erstellen, indem man in der Kommandozeile folgenden Befehl eingibt.

ssh-keygen -t rsa -C "your_email@example.com

Es sollte diese Meldung erscheinen:

Enter file in which to save the key (/c/Users/<Benutzername>/.ssh/id_rsa):

Diese mit Enter bestätigen. außer dort ist nicht der oben angegebene Pfad angegeben, dann diesen ändern in „C:\Users\<Benutzername>\.ssh\id_rsa“ und mit Enter bestätigen.

Dann wird noch nach einer „passphrase“ gefragt; hier bestätige ich einfach 2 mal.

Zum Schluss muss eine Meldung erscheinen, die lautet „The key fingerprint is: …“ dann sollte das Erstellen geklappt haben, wenn keine Fehlermeldung aufgetaucht ist.

Setup5

Hier noch ein Screenshot mit der cmd:

Punkt 3: Jetzt muss man noch den erstellten Key bei Github oder anderem Git dienst eintragen.

Dazu öffnet man die eben erstellte „C:\Users\<Benutzername>\.ssh\id_rsa.bup“ mit dem Winows Editor und kopiert den Inhalt der Datei eins zu eins bei Github in das Key Feld, welches erscheint, wenn man auf Add Keys klickt. Den Namen kann man leer lassen, da dieser automatisch eingetragen wird.

Punkt 4: Testen, ob der Key akzeptiert wird, macht man indem man nochmal die cmd öffnet und folgenden Befehl eingibt: ssh -T git@github.com

Wenn die Meldung „The authenticity of host ‚github.com (207.97.227.239)‘ can’t be established. RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48. Are you sure you want to continue connecting (yes/no)?“ erscheint einfach yes eingeben und bestätigen.

Setup6

Wenn alles geklappt hat, sollte eine Meldung wie im Screenshot erscheinen.

Damit kann mit Git mit SSH ohne Passworteingabe nutzen. Wichtig ist natürlich, dass man die Repros per SSH cloned und nicht per http.

Update 13.04.2015: Ich muss neuerdings die Umgebungsvariable set HOME=%HOMEDRIVE%%HOMEPATH% setzen damit ich mich über ssh authentifizieren kann. Die habe ich in den Windows Umgebungsvariablen bei meinem Benutzer gesetzt.

iPhone sync ohne Google Sync

Ich habe gestern hier gelesen, dass bei Google Sync (Active Sync. mit Gmail), zum 30.01.2013 für neue Nutzer abgeschaltet wird und dann nur noch mit den kostenpflichtigen Accounts möglich ist.

Deshalb habe ich mir mal angesehen (obwohl ich nicht betroffen sein sollte), wie ich weiterhin mein iPhone/iPad Synchronisieren kann.

Dabei musste ich feststellen, dass es eigentlich ganz einfach einzurichten ist und sogar einige Probleme behebt.

Zum Synchronisieren von Mail, Kalender und Notizen (ging mit Goggle Sync nicht) bedarf es nichts weiter als beim Hinzufügen eines Accounts, Gmail auszuwählen und seine Login Daten zu hinterlegen. Einziger Nachteil den ich bisher gefunden habe, ist, dass die Gmail Adresse auch gleichzeitig die Absenderadresse ist. Die Synchronisation wird dann per IMAP mit dem Gmail Konto durchgeführt. Der Kalender wird per CalDAV synchronisiert und die Notizen landen im IMAP Ordner Notes. Den Nachteil mit den Absenderadresse umgehe ich, indem ich die Gmail App installiert habe und diese zum Mailen verwende. Die App nutzt auch die Signaturen, die man in seinen Gmail Konto eingerichtet hat und man kann mit den liebgewonnen Labels vernünftig arbeiten. Dadurch, dass ich jetzt beides eingerichtet habe, kann ich zur Not auch noch direkt aus einer anderen App eine Mail verschicken. Ein weiterer Vorteil ist, dass man direkt alle seine Google Kalender zur Verfügung hat und diese nicht erst über eine extra Internetseite freischalten muss. Den Geburtstagskalender vom Google Kalender habe ich allerdings abgewählt, da ich nicht alle Geburtstage doppelt haben wollte.

Die Kontakte Synchronisation muss man, ich denke zurzeit noch, extra einrichten. Dazu richtet man ein zusätzlichen Account für CardDAV ein. Der Server Name ist google.com, plus die Google Account Daten. Damit geht dann auch die Synchronisation der Kontakte. Im Moment sieht es so aus als würde das auch besser funktionieren als mit Google Sync (Active Snyc.) zumindest scheint es so, dass sich die Felder in den Adressen nicht mehr wahrlos umbenennen und ich hoffe, dass Geburtstage sich nicht mehr verschieben.

Alles in allem scheint es keinen Nachteil durch das „abschalten“ von Google Sync zu geben und man braucht auch keine extra Sync. Software zu installieren.

iPhone Google Sync einrichten

Mal wieder einige der Dinge, die ich öfter wiedersuche. Wie richte ich mein iPhone mit Google Sync. (Exchange Aktive Sync.) ein.

Das wird auf der Seite http://support.google.com/mail/bin/answer.py?hl=de&answer=138740&topic=21161&ctx=topic sehr gut beschrieben.

Was aber wichtig zu wissen ist, dass man auch mehrere Kalender synchronisieren kann und auch einstellen kann, welche die Standard Absender Adresse ist. Wo man das macht, ist hier beschrieben: http://support.google.com/mobile/bin/answer.py?hl=en&answer=139206
Wichtig ist dabei die Sprache auf Englisch (US) umzustellen.

Die Punkte im Einzelnen:

  • ‚Enable „Send Mail As“ for this device‘. Bedeutet, dass der Standard Absender aus dem Gmail Account genommen wird.
  • ‚Enable „Delete Email As Trash“ for this device‘. Bedeutet, dass wenn man Mails löscht, diese nicht archiviert werden, sondern wirklich gelöscht werden (im Papierkorb landen).
  • Dann kann man noch einstellen, welche Kalender man synchronisieren möchte.

WordPress Links Menü Walker

Hier eine kleine Walker Klasse für WordPress, um sich ein Menü in der Form “ Link1 | Link2 | Link3 “ zu erstellen.

Einfach die Klasse in die functions.php des Themes und den Menü Eintrag dort im Template platzieren, wo er hin soll.

<?php
wp_nav_menu(
   array(
      'container'      => FALSE,
      'menu'           => 'The Footer Links',
      'menu_class'     => 'nav',
      'theme_location' => 'footer-nav',
      'items_wrap'     => '<nav id="%1$s" class="%2$s" role="navigation">%3$s</nav>',
      'depth'          => 1,
      'walker'         => new Links_Walker_Nav_Menu()
   )
);

class Links_Walker_Nav_Menu extends Walker_Nav_Menu {

   function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {

      //Add attributes to link element.
      $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) . '"' : '';
      $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) . '"' : '';
      $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) . '"' : '';
      $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) . '"' : '';
      $attributes .= ( $item->current ) ? ' class="active"' : '';

      $output .= ( $item->menu_order > 1 ) ? ' | ' : '';
      $output .= '<a' . $attributes . '>';
      $output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
      $output .= '</a>';

   }

   function end_el( &$output, $item, $depth = 0, $args = array() ) {

      $output .= '';
   }

}

Standard WordPress Plugin Funktionen

Zwei der Funktionen/Methoden, die man in Zukunft wohl in allen meinen Plugins finden wird, sind:
Voraussetzung ist PHP 5.1.2 für die Autoload Funktion.

1. Zum Ermitteln von Plugin Daten, damit nicht immer alles per Constante definiert wird, um Namensraum freizuhalten:

<?php
public static function get_plugin_data( $get_data = FALSE ) {

	$plugin_data = wp_cache_get( 'plugin_data', 'pluginname' );
	if ( $plugin_data === FALSE || empty( $plugin_data[ 'Version' ] ) ) {
		$plugin_data               = get_file_data(
			__FILE__, array(
				'Name'        => 'Plugin Name',
				'PluginURI'   => 'Plugin URI',
				'Version'     => 'Version',
				'Description' => 'Description',
				'Author'      => 'Author',
				'AuthorURI'   => 'Author URI',
				'TextDomain'  => 'Text Domain',
				'DomainPath'  => 'Domain Path'
			), 'plugin'
		);
		$plugin_data[ 'BaseName' ] = plugin_basename( __FILE__ );
		$plugin_data[ 'Folder' ]   = dirname( plugin_basename( __FILE__ ) );
		$plugin_data[ 'URL' ]      = plugins_url( '', __FILE__ );
		if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
			$plugin_data[ 'JSVersion' ] = time();
		} else {
			$plugin_data[ 'JSVersion' ] = $plugin_data[ 'Version' ];
		}
		wp_cache_add( 'plugin_data', $plugin_data, 'pluginname' );
	}

	if ( ! $get_data ) {
		return $plugin_data;
	}

	return $plugin_data[ $get_data ];
}

2. Die Autoload Funktion von PHP zum automatischen Laden von Klassen, damit sie nur dann geladen werden, wenn sie auch benötigt werden. Das heißt, verwendet man ein „add_action“ wird die Klasse erst geladen, wenn wirklich ein „do_action“ erfolgt oder die Seitenklasse für einen Menüeintrag erst geladen wird, wenn der Menüpunkt tatsächlich aufgerufen wird. Voraussetzung ist, dass man das ganze Plugin klassenbasierend aufbaut. Das kann dann nicht nur Ressourcen sparen.

<?php
public function __construct() {
	//register autoloader
	spl_autoload_register( array( $this, 'autoloader' ) );
}

public static function autoloader( $class_name ) {
	//WordPress classes loader
	$wpclass='/class-'.strtolower(str_replace('_','-',$class_name)).'.php';
	if ( is_file(ABSPATH .'wp-admin'.DIRECTORY_SEPARATOR.'includes'.$wpclass) ) {
		require(ABSPATH .'wp-admin'.DIRECTORY_SEPARATOR.'includes'.$wpclass);
		return true;
	}
	if ( is_file(ABSPATH . WPINC . $wpclass) ) {
		require(ABSPATH . WPINC . $wpclass);
		return true;
	}

	//Plugin classes to load
	if ( strpos( $class_name,'PluginClass_') !== false ) {
		$class_load = dirname( __FILE__ ) . DIRECTORY_SEPARATOR.'inc'.DIRECTORY_SEPARATOR.'class-' . strtolower( str_replace( array( 'PluginClass_', '_' ), array( '', '-' ), $class_name ) ) . '.php';
		if ( is_file( $class_load ) ) {
			require($class_load);
			return true;
		}

	}
	return false;
}

Diese sollten sich innerhalb der Haupt Plugin Datei in einer Klasse befinden.

PHP Verzeichnis Übergabe prüfen

Ich muss in meinem Plugin für WordPress den ABSPATH übergeben, um eine eigene Ajax Behandlung zu haben.
Was meint ihr ist der Codeschnipsel dafür geeignet, um es möglicht sicher gegen Angriffe zu machen?

<?php
if ( is_file( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . '/wp-load.php' ) ) {
	require_once( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . '/wp-load.php' );
} else {
	$abspath = filter_input( INPUT_POST, 'ABSPATH', FILTER_SANITIZE_URL );
	$abspath = rtrim( realpath( $abspath ), '/' );
	if ( ! empty( $abspath ) && is_dir( $abspath . '/' ) && is_file( realpath( $abspath . '/wp-load.php' ) ) ) {
		require_once( $abspath . '/wp-load.php' );
	} else {
		die();
	}
}

Erläuterung:
Wenn der Plugins Ordner im Standard Verzeichnis ist oder zumindest in der selben Verzeichnis Tiefe muss die Übergabe nicht genutzt werden.
Sonst.
Das übergebene Verzeichnis vorfiltern (nur in URLs erlaubte Zeichen werden zugelassen)
mit ‚realpath()‘ alle ‚../‘,‘./‘ entfernen und prüfen, ob das Verzeichnis existiert.
Da ‚realpath()‘ auch das aktuelle Verzeichnis ausgibt nochmal Verzeichnis und Datei auf Existenz prüfen.
WP-load.php laden.

Ressourcen sparen bei Ajax Calls in WordPress

Bei meiner Arbeit am Plugin BackWPup habe ich nach einer Möglichkeit gesucht Ressourcen bei Ajax Calls und bei der Auftragsausführung zu sparen. Die einzige große Einsparung, die ich bisher gefunden habe, ist es die Übersetzungen anderer Plugins nicht mit zu laden, da die enorm viel Speicher verbrauchen. Dies bringt in meiner Testinstallation mit 20 Plugins eine Einsparung von 31 MB auf 25,5 MB Script Speicher. Da die Dateien auch nicht geöffnet werden, wird das auch noch eine Einsparung bringen, die ich im Moment nicht beziffern kann.

Hier die Umsetzung:
Wichtig ist hierbei, dass ich nur die Übersetzungen nicht lade, wenn es sich um Calls meines Plugins handelt.

<?php
define( 'PLUGIN_MENU_PAGES', 'page1,page2' );
if ( defined( 'DOING_AJAX' ) and DOING_AJAX and in_array(
		$_POST[ 'backwpupajaxpage' ], explode( ',', PLUGIN_MENU_PAGES )
	)
) {
	add_filter(
		'override_load_textdomain', create_function(
			'$default, $domain, $mofile', 'if ($domain=="textdomain") return $default; else return true;'
		), 1, 3
	);
}

Zusätzlich musste ich noch einbauen, dass mein Plugin als erstes geladen wird:

<?php
define( 'PLGUNINNAME_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );

public function pluginname_first_plugin( $newvalue, $oldvalue ) {

	if ( ! is_array( $newvalue ) ) {
		return $newvalue;
	}
	for ( $i = 0; $i < count( $newvalue ); $i++ ) {
		if ( $newvalue[ $i ] == PLGUNINNAME_PLUGIN_BASENAME ) {
			unset( $newvalue[ $i ] );
		}
	}
	array_unshift( $newvalue, PLGUNINNAME_PLUGIN_BASENAME );

	return $newvalue;
}

add_filter( 'pre_update_option_active_plugins', 'pluginname_first_plugin', 1, 2 );

Vielleicht kennt ja noch jemand eine Lösung die Ressourcen weiter zu optimieren und die WordPress eigene Ajax Behandlung zu nutzen…

Update:
mit einer etwas geänderten Funktion ist es nicht mehr notwendig das Plugin nach vorne zu schieben.

<?php
define( 'PLUGIN_MENU_PAGES', 'page1,page2' );
function overide_textdomain( $default, $domain, $mofile ) {

	if ( ( defined( 'DOING_CRON' ) && DOING_CRON )
		&& in_array(
			$_POST[ 'backwpupajaxpage' ], explode( ',', PLUGIN_MENU_PAGES )
		)
	) {
		global $l10n;
		if ( $domain == 'owntextdomainname' ) {
			foreach ( array_keys( $l10n ) as $domainkey ) {
				unset( $l10n[ $domainkey ] );
			}
		} else {
			return TRUE;
		}
	}

	return $default;
}

add_filter( 'override_load_textdomain', 'overide_textdomain' );

Update: Ich glaub das beste ist es, wenn in WordPress der WP-Performance-Gettext-Patch integriert wird. Nach meinen Tests bringt das am meisten. Der Speicherverbrauch geht dann auf ca. 17MB runter.

WordPress 3.3 add_contextual_help deprecated

Eine einfache Möglichkeit festzustellen, ob man mit „add_contextual_help()“ oder „get_current_screen()->add_help_tab“ arbeiten muss, um die abwärts Kompatibilität zu behalten.

<?php
if (method_exists(get_current_screen(),'add_help_tab')) {
    get_current_screen()->add_help_tab( array(
        'id' => 'plugininfo',
        'title' => 'Plugin Info',
        'content' => 'Text') );
} elseif (function_exists('add_contextual_help')) {
    add_contextual_help( get_current_screen(), 'Text');
}

WoW Account gehackt

Ich weiß nicht, ob ich lachen oder weinen soll. Mein WoW-Account wurde gehackt!
Spielen tue ich seit ca. 3 Monaten nicht mehr und mein Passwort ist auch kein 08/15, sondern eins aus einem Passwort Generator.

Mich erreichte um 14:46 Uhr die Mail, dass mein Account Passwort zurückgesetzt wurde.

Wir haben eine Anfrage für die Zurücksetzung Ihres Passworts für Ihren Battle.net-Account erhalten. Bitte klicken Sie auf diesen Link, um Ihr Passwort zurückzusetzen:

ca: 15:00 Uhr
Als ich die Mail gelesen habe, habe ich direkt reagiert und mich versucht in den Account einzuloggen, was nicht ging, weil das Passwort falsch war. Also habe ich direkt mein Passwort zurückgesetzt. Das klappte.

Ich konnte in meinem Account sehen, dass ich eine 7 Tage Spielzeit bekommen habe, dass ein Level 1 Char erstellt wurde. Außerdem habe ich zumindest gesehen, dass auf Xiok das ganze Gold weg ist. Dann hat Xiok vor 3 Stunden einen Erfolg errungen, daher gehe ich davon aus, dass er sich dann das erste Mal eingeloggt hat.

Habe dann direkt Blizzard und meine Gilde benachrichtigt.
Blizzards erste Antwort war mal wieder die Standard Antwort von wegen Virenscan Phishing usw.
Mal sehen wie es weiter geht.

Update: mein Account wurde wiederhergestellt. Möchte dennoch gerne mal wissen, wie die an mein Passort gekommen sind