Zum Inhalt springen

Benutzer:Summer ... hier!/wiki-upload.cli.php

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 13. September 2014 um 15:32 Uhr durch Summer ... hier! (Diskussion | Beiträge) (Programmtext). Sie kann sich erheblich von der aktuellen Version unterscheiden.

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).

Intallation / 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 Configdatei "~/.<Programmname>.config" im Homeverzeichnis an. In der Datei muss user und password eingeragen 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 "*.JPG" 
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) in /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 


// 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";
$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
|Description    ={{de|Beschreibung folgt}} 
|Source         ={{own}}
|Author         = ~~~~
|Date           = 2014-
|Permission     =
|other_versions = {{de|Mit PHP-Script (curl) hochgeladen}}
}}
{{Information
|Beschreibung     = Beschreibung folgt
|Quelle           = selbst fotografiert
|Urheber          = ~~~~
|Datum            = 2014
|Genehmigung      = 
|Andere Versionen = 
|Anmerkungen      = Mit PHP-Script (curl) hochgeladen}
}}
== {{int:license-header}} ==
{{Bild-CC-by-sa/3.0}}
{{self|cc-by-sa-3.0}}
UPLOAD_FILE_TEXT;
?>
DEFAULT_CONFIG_NOWDOC;


function check_uploadfile()
{
  // Die hochzuladende Datei prüfen (hier wird z.Zt. nur auf 
  // die Existenz gefprüft) 
  
  // Das Array $settings global benutzen. 
  global $settings;

  // Der Name der Upload-Datei ist der erste Programmparameter
  $settings['upload_file_name']  =  $GLOBALS['argv'][1];
  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 Inlcuden 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 solle $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 hart ... 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 () 
{
  // 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&amp;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  =  "action=query"; 
  $params .= "&meta=tokens"; 
  //$params .= "&type=edit";
  $params .= "&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);

  // 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", 
                  'text'     => "${settings['upload_file_text']}",
                  'filename' => "${settings['upload_file_name']}",
                  'file'     => "@${settings['upload_file_name']}",
                  '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 ;
}




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. 
die();
?>

Nun sind wir tot und haben nicht einmal Tschüss gesagt ...