Benutzer:Summer ... hier!/wiki-upload.cli.php
Script zum Upload von Bildern
Zweck / Funktion / Umgebung
Dieses Script läuft unter unixoiden Systemen auf denen PHP (ab 5.3) mit der curl Erweiterung installiert ist. Es ist ein Kommandozeilentool (CLI - Command Line Interface).
Installation / Aufruf
Den Code in eine beliebige Datei kopieren und die Datei mit "chmod u+x <Dateiname>" als ausführbar markieren. Aufgerufen wird es mit "./<Programmname> <Bilddatei>". Beim ersten Aufruf legt das Programm eine Konfigurationsdatei "~/.<Programmname>.config" im Homeverzeichnis an (Anmerk.: der Name der Konfigurationsdatei beginnt mit "." - bei Unixoiden steht der Punkt für "versteckte Datei"). In der Konfigurationsdatei muss user und password eingetragen werden.
Der lokale Name der Bilddatei wird bei Wiki übernommen. Vorher also der Datei einen vernünftigen Namen geben!
Mehrere Bilder können in einer For-Schleife hochgeladen werden:
for Datei in $(ls *.[j,J][p,P][g,G])
do
<Programmname> $Datei
done
Sicherheit
Bei dem Programm wurde kein Wert auf Sicherheit gelegt. Insbesondere das Abspeichern von Passwörtern in Dateien ist nicht sicher. Auch werden Protokolldaten (einschl. Password) im Verzeichnis /tmp abgelegt. Das Programm kann aber natürlich um Sicherheitsaspekte erweitert werden.
Programmtext
#!/usr/bin/php -f
<?php
// Wichtigste Quelle:
// https://www.mediawiki.org/wiki/User:Bcoughlan/Login_with_curl
// über
// https://www.mediawiki.org/wiki/API:Login
function check_uploadfile()
{
// Die hochzuladende Datei prüfen (hier wird z.Zt. nur auf
// die Existenz geprüft)
// Das Array $settings global benutzen.
global $settings;
if (!file_exists($settings['upload_file_name']))
{
throw new Exception("upolaodfile don't exist - check the first parameter of this porgramm");
}
}
function read_configfile()
{
// Das Array $settings global benutzen.
global $settings;
// Name dieses Programms ohne Pfadangabe der Variablen
// $settings;['base___FILE__'] zuweisen.
$settings['my_filename'] = basename( __FILE__ );
// Anmerkung: da diese Var. zur Benennung der Konfig-Dateien benutzt
// wird, wirken sich Namensänderungen dieses Programms auch automatisch
// auf die Namen der Konfig-Dateien aus.
// Home Verz. ermitteln (kann in $_SERVER und mal in $_ENV stehen)
if (isset($_SERVER['HOME'])) {$settings['my_HOME'] = $_SERVER['HOME'];};
if (isset( $_ENV['HOME'])) {$settings['my_HOME'] = $_ENV['HOME'];};
if (empty($settings['my_HOME']))
{
throw new Exception("Error getting enviroment var. HOME \n");
}
// den Dateinamen für die Konfig-Datei im Home-Verz. festlegen.
$settings['home_configfilename'] = "${settings['my_HOME']}/.${settings['my_filename']}.config";
// Falls die Konfig-Datei im Home-Verz. nicht existiert ...
if (!file_exists($settings['home_configfilename']))
{
// ... Anlegen der Datei ...
file_put_contents($settings['home_configfilename'], $GLOBALS['default_config']);
if (file_exists($settings['home_configfilename']))
{
throw new Exception("${settings['home_configfilename']} created - pleas edit the file");
}
// ... und falls sie nicht angelegt werden konnte:
else
{
throw new Exception("can't create configfile ${settings['home_configfilename']}");
}
}
// Nun Includen wir die Konfig-Datei
require($settings['home_configfilename']);
// Testen ob der Include funktioniert hat:
if (empty($settings['wikiroot']))
{
throw new Exception("${settings['home_configfilename']} not includet");
}
// Falls direkt neben der Programmdatei auch eine Konfig-Datei liegt
// wird diese ebenfalls eingelesen.
if (file_exists(__FILE__ . ".config"))
{
require(__FILE__ . ".config");
}
}
function httpRequest($url, $post="")
{
// Ueber diese Funktion findet die Kommunikation zum WIKI-Server statt.
// Die oben definieten Variablen hier nutzen
global $settings;
$ch = curl_init();
// Allgemeine Werte für die Kommunikation festlegen.
curl_setopt ($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9');
curl_setopt ($ch, CURLOPT_URL, ($url));
curl_setopt ($ch, CURLOPT_ENCODING, "UTF-8" );
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt ($ch, CURLOPT_COOKIEFILE, $settings['cookiefile']);
curl_setopt ($ch, CURLOPT_COOKIEJAR, $settings['cookiefile']);
// Hier kommen die Post-Daten hinzu
if (!empty($post)) curl_setopt($ch,CURLOPT_POSTFIELDS,$post);
// Geschwätziges Protokoll in $settings['curl_verbose_file'] ausgeben.
// Achtung: auf Rechnern mit mehreren Benutzern koennen diese die
// Protokolldaten u.u. einsehen (nebst Passwörter etc.).
if (!@isset($settings['curl_log']))
{
// Keine Ahnung warum, aber mit "fopen(handle,'w')" schreibt curl
// nicht alle Daten ins Logfile ... Option 'a' in Kombination mit
// "seek()" ist ein Workarount.
// Wer bedenken hat, dass die Daten von einem Mitbenutzer des
// Rechners missbraucht werden sollte $curl_verbose_file auf "/dev/null"
// seten.
$settings['curl_log'] = fopen($settings['curl_verbose_file'], 'a');
fseek ($settings['curl_log'] , 0);
};
fwrite($settings['curl_log'], "#-POST-#" . print_r($post, true) . "#-POST-#\n");
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $settings['curl_log']);
// curl Anfrage absetzen
$xml = curl_exec($ch);
if (!$xml)
{
throw new Exception("Error getting data from server ($url): " . curl_error($ch));
}
curl_close($ch);
// Ausgabe der Antworten des Wiki-Server
// (bischen viele Konsolenausgaben ... aber man kanns ja rauswerfen ...)
echo "Response of http:Request (Begin)\n";
$dom = new DOMDocument();
$dom->loadXML($xml);
$dom->preserveWhiteSpace = FALSE;
$dom->formatOutput = TRUE;
$x=$dom->saveXML();
// echo htmlspecialchars($x);
echo $x;
echo "(End)\n";
// Rueckgabe
return $xml;
}
function login ($user, $pass, $token='')
// Diese Funktion hat zwei Aufgaben: wird sie nur mit $user und $pass
// aufgerufen, so holt sie nur einen Token zum Login beim Wikiserver.
// Erst beim zweiten Aufruf dieser Funktion mit $token logt man sich
// beim Wikiserver ein.
// ACHTUNG: beim zweiten Aufruf enthält das Ergebnis einen lgtoken.
{
// ganz oben definiertes Array §settings hier nutzen
global $settings;
// an den Servernamen den Pfad dranhaengen
$url = $settings['wikiroot'] . "/w/api.php";
// Parameter fuer Aufruf zusammenbauen
$params = "action=login";
$params .= "&lgname=$user";
$params .= "&lgpassword=$pass";
$params .= "&format=xml";
// Falls dieser Funktion der Paramter $token übergeben wurde uebergeben
// wir ihn als Parameter (beim Aufruf des Wikiservers ohne Token erhalten
// wir einen solchen).
if (!empty($token))
{
$params .= "&lgtoken=$token";
}
// den Wikiserveraufruf absetzen
$xml_str = httpRequest($url, $params);
// Wenn der Aufruf absolut keine Antwort ergab geben wir eine Meldung raus.
if (empty($xml_str))
{
throw new Exception("No data received from server. Check that API is enabled.");
}
// Die XML-Antwort in ein Array umwandeln.
$xml_obj = simplexml_load_string($xml_str);
if (!empty($token))
{
//Check for successful login
$expr = "/api/login[@result='Success']";
$result = $xml_obj->xpath($expr);
if(!count($result))
{
throw new Exception("Login failed");
}
}
else
{
$expr = "/api/login[@token]";
$result = $xml_obj->xpath($expr);
if(!count($result))
{
throw new Exception("Login token not found in XML");
}
}
return $result[0]->attributes()->token;
}
function logout ()
{
// Achtung: bei Ausloggen ist wiki zwiemlich gruendlich. Auch Sessions von
// anderen Rechnern werden beendet!
//
// ganz oben definiertes Array §settings hier nutzen
global $settings;
// an den Servernamen den Pfad dranhaengen
$url = $settings['wikiroot'] . "/w/api.php";
// Parameter fuer Aufruf zusammenbauen
$params = "action=logout";
$params .= "&format=xml";
// Falls dieser Funktion der Paramter $token übergeben wurde uebergeben
// wir ihn als Parameter (beim Aufruf des Wikiservers ohne Token erhalten
// wir einen solchen).
// den Wikiserveraufruf absetzen
$xml_str = httpRequest($url, $params);
}
function get_edittoken()
{
/* Habe urspruenglich wie in https://www.mediawiki.org/wiki/API:Tokens
beschrieben mir einen edit-Token mit "action=token" etc. geholt.
Das funktinierte zwar, habe aber immer die Warnung "action=tokens
has been deprecated. Please use action=query&meta=tokens instead."
erhalten. Habe daher auf action/meta umgestellt. Bei der Serverantw.
heisst der Token nun auch "csrftoken" statt "token" (csrf steht fuer
"Cross-Site-Request-Forgery". */
// ganz oben definiertes Array §settings hier nutzen
global $settings;
// an den Servernamen den Pfad dranhaengen
$url = $settings['wikiroot'] . "/w/api.php";
// Parameter fuer Aufruf zusammenbauen
$params = array('action' => "query",
'meta' => "tokens",
'type' => "csrf", // Parameter type kann weg gelassen werden
'format' => "xml");
// Werte fuer type (mehrere mit '|' trennen): csrf, deleteglobalaccount, patrol,
// rollback, setglobalaccountstatus, userrights, watch (Default: csrf)
// den Wikiserveraufruf absetzen
$xml_str = httpRequest($url, $params);
// Wenn der Aufruf absolut keine Antwort ergab geben wir eine Meldung raus.
if (empty($xml_str))
{
throw new Exception("No data received from server. Check that API is enabled.");
}
// Die XML-Antwort in ein Array umwandeln.
$xml_obj = simplexml_load_string($xml_str);
// Ermitteln des Token
$expr = "/api/query/tokens[@csrftoken]";
$result = $xml_obj->xpath($expr);
if(!count($result))
{
throw new Exception("Login token not found in XML");
}
// Rueckgabe des Token
return $result[0]->attributes()->csrftoken;
}
function upload($token)
{
echo $token;
// ganz oben definiertes Array §settings hier nutzen
global $settings;
// an den Servernamen den Pfad dranhaengen
$url = $settings['wikiroot'] . "/w/api.php";
// Parameter fuer Aufruf zusammenbauen
$params = array('action' => "upload",
'comment' => "uploaded by script [[:de:Benutzer:Summer ... hier!/wiki-upload.cli.php]]",
'text' => "${settings['upload_file_text']}",
'filename' => "${settings['upload_file_name']}",
'file' => "@${settings['upload_file_name']}",
'watchlist' => "watch", // (moegl. Werte: watch, preferences, nochange)
// 'ignorewarnings' => "", // ohne Wert --> vorhandene Datei wird überschrieben
'token' => "$token",
'format' => "xml");
// den Wikiserveraufruf absetzen
$xml_str = httpRequest($url, $params);
// Wenn der Aufruf absolut keine Antwort ergab geben wir eine Meldung raus.
if (empty($xml_str))
{
throw new Exception("No data received from server. Check that API is enabled.");
}
// Die XML-Antwort in ein Array umwandeln.
$xml_obj = simplexml_load_string($xml_str);
return ;
}
/////////////// Beginn der Hauptprogramms /////////////
// Der Name der Upload-Datei ist der erste Programmparameter
$settings['upload_file_name'] = $GLOBALS['argv'][1];
// Anmerk.: bei einem Ausbau des Programms sollten die Optioenn mit getopt()
// Ausgewertet werden-
// Defaultwerte für die Konfigurationsdatei
//
// Achtung: hier drunter kommt ein nowdoc, kein heredoc!
// Nowdoc's werden nicht geparst (setzen aber Ver. 5.3 voraus)
// Das nowdoc entspricht dem Text einer Konfig-Datei in die u.a.
// username und password eingetragen werden muss ...
// Siehe nach dem ersten Programmdurchlaus ~/.<Name-dieses-Programms>.config
$default_config =<<<'DEFAULT_CONFIG_NOWDOC'
<?php
$settings['wikiroot'] = "http://de.wikipedia.org";
// ... oder = "http://commons.wikimedia.org"
$settings['user'] = "mein Wikiaccount";
$settings['pass'] = "mein Wikipassword";
$settings['cookiefile'] = "cookies.tmp";
$settings['curl_verbose_file'] = sys_get_temp_dir() . '/' . $settings['my_filename'];
$settings['upload_file_text'] =<<<UPLOAD_FILE_TEXT
{{Information
|Beschreibung = Beschreibung folgt
|Quelle = selbst fotografiert
|Urheber = ~~~~
|Datum = 2014
|Genehmigung =
|Andere Versionen =
|Anmerkungen = Mit [[:de:Benutzer:Summer ... hier!/wiki-upload.cli.php|PHP-Script (curl)]] hochgeladen
}}
== Lizenz ==
{{Bild-CC-by-sa/3.0}}
<!-- [[Kategorie:...]] -->
<!-- Text für Upload nach Commons
{{Information
|Description ={{de|Beschreibung folgt}}
|Source ={{own}}
|Author = ~~~~
|Date = 2014-
|Permission =
|Other_versions =
|Other fields = {{Information field|Name=comment|Value=Uploaded with [[:de:Benutzer:Summer ... hier!/wiki-upload.cli.php|PHP-Script (curl)]]}}
}}
== {{int:license-header}} ==
{{self|cc-by-sa-3.0}}
[[Category:Files by user ${settings['user']}]]
-->
UPLOAD_FILE_TEXT;
?>
DEFAULT_CONFIG_NOWDOC;
try
{
global $settings;
echo "########### call function check_uploadfile() - Uploadfile pruefen\n";
check_uploadfile();
echo "########### call function read_configfile() - Konfig-Datei(en) einlesen\n";
read_configfile();
echo "########### call function login() - Token holen\n";
$token = login($settings['user'], $settings['pass']);
echo "########### call funktion login() - jetzt wird eingelogt\n";
$null = login($settings['user'], $settings['pass'], $token);
echo "########### call function get_edittoken() - Token zum Editiren holen\n";
$edittoken = get_edittoken();
echo "value of the token: $edittoken \n";
echo "########### call function upload() - raus die Maus\n";
$null = upload($edittoken);
echo "########### call function logout() \n";
$null = logout();
}
catch (Exception $e)
{
fwrite(STDERR, "FAILED: " . $e->getMessage() . "\n");
if (@file_exists($settings['curl_verbose_file']))
{
fwrite(STDERR, "see also ${settings['curl_verbose_file']} \n");
};
die();
}
# Sterben ist bei CLI immer gut (damit eventueller Müll hinter dem PHP-Tag nicht ausgegeben wird).
die();
?>
Nun sind wir tot und haben nicht einmal Tschüss gesagt ...
Warum dieses Script???
Bevor ich dieses Script geschrieben habe, habe ich natürlich geguckt was es schon gibt:
Als erstes fand ich ein Script unter c:Commons:File upload service/Script. Das script ist von Benutzer:Eloquence (dem allseits bekannten Erik Möller) und leider als deprecated markiert. Weil das Script einfach zu installieren war, hab ich es trotzdem mal laufen lassen. Lief prima! Meldet ständig das meine Dateien erfolgreich hochgeladen seien ... nur gefunden habe ich hochgeladenen Dateien nie.
Das zweite Script das ich gefunden habe war c:User:Nichalp/Upload script. Als ich gelesen habe, dass zum Betrieb des Ganzen erst CSV Dateien (die zuvor mit irgendeinen ein CVS-creator-script erzeugt werden) bearbeitet werden müssen (OpenOffice.org Spreadsheet or Microsoft Office Word werden vorgeschlagen) haben sich mir die Krallen der Hinterläufe aufgerollt. Natürlich kann man auch CSV anderes bearbeiten ... man kann auch mit Katzen spielen ... das tut ja schon weh ...
Vielleicht gibts schon andere Upload-Scripte die gut sind. Habe aber nach zwei Reinfällen nicht danach gesucht. Wer was weiß kann sich gerne bei mir melden (oder es auch direkt hier eintragen ... ich behalte mir im zweifel aber Löschung auf meiner Benutzerseite vor).
Mir persönlich reicht das obige Script für meine Zwecke (auch wenn es alles andere als elegant ist). Wer Kriik hat und das Script ernsthaft nutzen möchte, der kann sich gerne melden. Ich bin für Weiterentwicklung offen wenn es Bedarf gibt.