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

Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 12. September 2014 um 20:07 Uhr durch Summer ... hier! (Diskussion | Beiträge). 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.

Mehrere Bilder können in einer For-Schleife hochgeladen werden.

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.

Programmtest

#!/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' => "Maus_auf_Kombizange_4.JPG",
                  '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 ...