Realisierung einer Druckfunktion auf der Basis von Google Cloud Print
Kommentare

Die Entwicklerbrille
Als Entwickler untersucht man sicherlich zunächst die verfügbaren APIs und versucht herauszufinden, welche Möglichkeiten sich hier ergeben. Google bietet uns im API zunächst zwei

Die Entwicklerbrille

Als Entwickler untersucht man sicherlich zunächst die verfügbaren APIs und versucht herauszufinden, welche Möglichkeiten sich hier ergeben. Google bietet uns im API zunächst zwei große Funktionsblöcke an. Zum einen ist das der Bereich, den ein Druckerhersteller nutzen würde, wenn ein Drucker zu integrieren ist. Diesen Bereich nennt Google Receiving Interface. Die Gegenseite dazu bildet das Submitting Interface, das für das Absenden eines Druckjobs genutzt werden kann. Die genaue Beschreibung der Web-Service-Schnittstelle befindet sich unter [3].

Aber schauen wir uns zunächst die genutzte Basistechnologie an. Grundsätzlich ist das Serviceinterface ein HTTP-basiertes einfaches Protokoll. Der Basis-URL [4] wird einfach um den Namen der Servicemethode erweitert. An den resultierenden URL wird ein HTTP Post abgesetzt. In den meisten Fällen reicht hier das Format form-urlencoded, also eine einfache Liste von Key-Value-Paaren aus. Für den Upload von Dokumenten wird hingegen ein so genanntes Multi-Part-Post genutzt. Das macht die Sache ein wenig komplexer, ist aber auch mit vertretbarem Aufwand schnell realisiert. Als Ergebnis des HTTP Request liefern uns die Google-API-Server immer ein JSON-Dokument zurück. In PHP können wir uns dann einfach mit json_decode ein äquivalentes PHP-Objekt erzeugen lassen.

Technologisch brauchen wir zum Absenden der Daten eine Realisierung des HTTP-Protokolls. Da wir keine SSL-Verbindung benötigen, könnten wir uns hier auch mit Hausmitteln behelfen und direkt eine Socket-Verbindung aufbauen. Sie werden aber gleich noch sehen, dass für die Authentifizierung die Nutzung von https zwingend notwendig ist. Daher habe ich mich in den Beispielen auf die cURL-Bibliothek gestützt, die sicherlich in kaum einer PHP-Installation fehlt. Allen Serviceaufrufen muss zwingend der HTTP Header Authorization: GoogleLogin auth=TOKEN beigefügt werden. Der Wert von TOKEN muss dabei zunächst durch eine Anmeldung unter dem Google-Konto ermittelt werden.

Für die Authentifizierung können aktuell eine Reihe unterschiedlicher Verfahren eingesetzt werden. Grundsätzlich soll hier mittelfristig für alle Google-Dienste OAuth2 genutzt werden. Derzeit ist aber auch die alte, vereinfachte Form der Anmeldung noch möglich. Für die Realisierung von OAuth stehen mittlerweile zahlreiche unterschiedliche Bibliotheken zur Verfügung.

Eine Realisierung der Anmeldung finden Sie in Listing 1. Der Aufbau ist ein HTTP Post auf eine spezielle Adresse. Dabei ist eine Reihe von Parametern maßgeblich: Neben dem obligatorischen Benutzernamen und einem Passwort ist auch der Dienst anzugeben, der genutzt werden soll. Für unsere Experimente nutzen wir cloudprint als Marker. Konnte das Benutzerkonto angemeldet werden, gibt der zentrale Anmeldedienst eine Reihe von Werten in der Form Schlüssel=Wert zurück. Alle Werte sind dabei durch Newlines separiert. Für uns ist lediglich der Schlüssel Auth interessant. Er stellt den Token für die Nutzung in den Serviceaufrufen dar. Zugegebenermaßen ist der vorliegende Code vollständig auf die Funktion reduziert, der Google-Dienst liefert im Fall von falschen Daten den Text Error=BadAuthentication zurück, der zumindest geprüft werden sollte.

Listing 1: Code für Authentication
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin");
$data = array(
  'accountType' => 'HOSTED_OR_GOOGLE',
  'Email' => $this->Email,
  'Passwd' => $this->Password,
  'source'=>'PHPMAG-GCP-SAMPLE',
  'service'=>'cloudprint'
);  
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

$authRawRet = curl_exec($ch);
curl_close($ch);

foreach (explode("n", $authRawRet) as $retValue) {
  if ($retValue) {
    list($code, $value) = explode("=", $retValue);
    $authData[$code] = $value;
  }
}
return $authData['Auth'];
Servicegrundlage

Schauen wir uns nun die Basisabläufe für die Absendung eines Druckjobs an (Listing 2). In der Dokumentation befindet sich hierzu im Bereich JOB SUBMISSION eine Reihe von Servicemethoden. Für die Realisierung brauchen wir zunächst die Adresse eines verfügbaren Druckers. Diese Adresse ist in der Cloud-Print-Terminologie die so genannte PrinterId. Besitzen wir die PrinterId, können wir ein zu druckendes Dokument an sie senden. Für die Ermittlung der ID benutzen wir die Methode /search. Hiermit können wir den Namen der verfügbaren Drucker und die ID abfragen. Typischerweise bieten wir die Drucker dem Benutzer unserer Anwendung in einer Liste an. Nun könnte man mit der Methode /printer eine detailierte Liste von Informationen über die Fähigkeiten eines Druckers abrufen. Daneben könnte man weiterhin die so genannten Jobs abrufen (/jobs) und sie eventuell, solange sie noch nicht gedruckt wurden, mit /deletejob löschen.

Listing 2: Einfacher Serviceaufruf
$ch = curl_init();
$reqHeaders[] = 'Authorization: GoogleLogin auth=' . $this->GoogleAuthToken;
$message = "";

$reqHeaders[] = 'Content-Type: application/x-www-form-urlencoded';
if (count($dataParams)) {
  foreach ($dataParams as $key => $value) {
    $msg[] = $key . '=' . $value;
  }
  $message = implode('&', $msg);
}
$reqHeaders[] = 'Content-Length: ' . strlen($message);
    
curl_setopt( $ch, CURLOPT_HTTPHEADER, $reqHeaders );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $message);
curl_setopt( $ch, CURLOPT_URL, $this->serviceEndPoint . $serviceName);
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    
$responseRaw = curl_exec( $ch );

Für das Initiieren eines Ausdrucks nutzen wir die Methode /submit. Wesentlich ist hier das Feld content, das den Inhalt des Dokuments beinhaltet. Die Art der Daten wird hier durch ein weiteres Feld (contentType) beschrieben. Gibt man hier einfach url an, darf sich im Feld content einfach ein URL befinden, der evaluiert wird. Hierbei ist zu beachten, dass der URL öffentlich erreichbar sein muss. Alternativ dürfen im Feld contentType application/pdf image/jpeg oder image/png angegeben werden. Entsprechend ergibt sich aus diesem Mime Type die Art der Daten, die nun in content zu übergegeben sind. Wichtig ist, dass bei der Übergabe der Inhaltsdaten der HTTP Post als multi-part mime realisiert werden muss. Der Code, der den Service realisiert, nimmt auch direkt Binärdaten entgegen, wenn die entsprechenden Header angegeben werden. Den hier genutzten Beispielcode finden Sie in Listing 3.

Listing 3: Komplexer Serviceaufruf mit Multipart
$boundary = "MIME_boundary";
$CRLF = "rn";

$mp_message = "";
foreach ($dataParams as $key => $value) {
  $mp_message .= "--" . $boundary . $CRLF;
  $mp_message .= 'Content-Disposition: form-data; name="' . $key . '"' . $CRLF . $CRLF;
  $mp_message .= $value . $CRLF;
}
$mp_message .= "--" . $boundary . $CRLF;
$mp_message .= 'Content-Disposition: form-data; name="content"; filename="' 
   . $filename . '"' . $CRLF;
$mp_message .= "Content-Transfer-Encoding: binary" . $CRLF;
$mp_message .= "Content-Type: application/octet-stream" . $CRLF . $CRLF;
$mp_message .= $multiPartData . $CRLF;
$mp_message .= "--" . $boundary . "--" . $CRLF;
  
$message = $mp_message;
  
$reqHeaders[] = 'Content-Type: multipart/form-data; boundary=' . $boundary;

Diese Herangehensweise spart einige Verarbeitungszeit, da auf das aufwendige Kodieren nach base64 verzichtet werden kann. Eventuell müssen wir daher zuvor unsere zu druckenden Daten zum

Beispiel in ein PDF-Dokument umwandeln und können dieses dann weiterleiten. Die Erstellung von PDF liegt außerhalb unserer Implementierung. Hierzu existieren aber bereits viele Lösungsansätze.

Ein Großteil der Interfaces wurde bei einer Beispielimplementierung einiger PHP-Klassen mit minimalen Abhängigkeiten realisiert. Den Quellcode finden Sie als Download auf www.phphmagazin.de. Des Weiteren zeigt Listing 4 die Nutzung der Klasse.

Listing 4: Nutzen des Service und Druck nach Google Docs
require_once 'GoogleCloudPrint.class.php';
$mail = ''; $pwd  = '';
$cp = new gcpSubmission($mail, $pwd);
echo "
" . print_r($cp->search(), true);
$cp->submitUrl('__google__docs', 'Sample', 'http://pastie.org/3977567');
Google Web Elements

Neben dem zwar nicht übermäßig anstrengenden Weg unter Nutzung des Serviceinterface existiert noch ein weiterer Weg, mithilfe von einigen Zeilen JavaScript-Code einen Ausdruck zu realisieren. Eine Beschreibung und ein Beispielcode befinden sich unter [5]. Wichtig ist jedoch zu beachten, dass sich hier der Ausdruck nur für Seiten realisieren lässt, deren URL öffentlich beziehungsweise von den Google-Servern erreichbar ist.

Fazit

Die Realisierung einer Druckfunktion auf Basis von Google Cloud Print lässt sich mit PHP ohne größere Probleme umsetzen. Grundsätzlich muss hierbei beachtet werden, dass sich ein Ausdruck zunächst für einen nicht weiter kontrollierbaren Zeitraum auf einem Server in der Google Cloud befindet. Für Dokumente, die eine gewisse Vertraulichkeit besitzen, ist es sicherlich nicht ganz unproblematisch. Eventuell ließe sich hier mithilfe einer eigenen Implementierung des Drucker-Proxys eine zusätzliche Sicherheitsebene einziehen. Höchst interessant ist auch die Möglichkeit, beliebige Webinhalte in Google-Docs-Dokumente umwandeln zu können.

Carsten Harnisch ist Technology Scout und arbeitet als Geschäftsführer bei der InTradeSys Limited.
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -