Klaus1: Aufruf in Include-File funktioniert, außerhalb nicht?

Hallo,

ich habe selbstgebaute PHP-Funktionen, die ich per Include in meinem Script einbaue, um sie zu verwenden. Die Funktionen rufen wiederum die REST-API von Moodle auf.

Im konkreten Fall lasse ich mir alle verfügbaren Kurse auflisten.


function moodle_call_rest_api($url) {
	// Make the HTTP request
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	$response = curl_exec($ch);
	curl_close($ch);
	return $response;
}

function moodle_get_courses() {
	global $token, $url;
	// Set up the request parameters
	$params = array(
		'wstoken' => $token,
		'wsfunction' => 'core_course_get_courses',
		'moodlewsrestformat' => 'json'
	);

	// Build the URL with the parameters
	$url .= '?' . http_build_query($params);
	$response = moodle_call_rest_api($url);

	// Process the response
	$data = json_decode($response, true);

	return $data;
}

Rufe ich die Funktion direkt innerhalb der Include-Datei auf, wird das gewünschte und erwartete Ergebnis zurückgeliefert.

$result = moodle_get_courses();
var_dump($result);

Rufe ich aber dieselbe Funktion in meinem Script auf, bekomme ich als Fehlermeldung aus Moodle "invalid parameters" zurück.

include ("moodle_functions.php");
$result = moodle_get_courses();
var_dump($result);
array(3) { 
	["exception"]=> string(27) "invalid_parameter_exception" 
	["errorcode"]=> string(16) "invalidparameter" 
	["message"]=> string(25) "Ungültiger Parameterwert" 
} 

Andere Funktionen aus dem Include-File lassen sich aber problemlos aufrufen. Die Funktionen sind alle identisch aufgebaut. Warum funktioniert "nur" diese nicht? Welchen Unterschied macht es, dass wo die Funktion aufgerufen wird? Der Include integriert doch den Inhalt, als wenn er im Script selber stehen würde, oder nicht?

LG Klaus

  1. Hallo Klaus1,

    hast Du überprüft, was in beiden Fällen in $token, $url und $params steht? Aus meiner Sicht muss da etwas abweichen.

    Es wäre auch sinnvoll, $token und $url nicht global abzulegen, sondern der Funktion als Argument zu übergeben. Global ist bäh.

    Alternativ mach eine Klasse Moodle, wo token und url als Eigenschaften hinterlegt sind, und get_courses kann dann eine Methode davon sein. Mit Klassen tut man sich oft leichter, seine Daten sinnvoll zu strukturieren. Grundlegende Lektüre.

    Ich weiß nicht, wo das Token herkommt. Klingt nach einem API-Schlüssel oder einer Art Session-ID - das Beschaffen dieses Tokens kann auch in einer Methode landen.

    class Moodle {
       private $url;
       private $token;
    
       public function __construct($url = "https://moodel.dee.doo") {
          $this->url = $url;
       }
    
       public function getToken($blub) {
          $this->token = /* do some magic */;
       }
    
       public function getCourses() {
          return $this->getJsonData('core_course_get_courses')
       }
    
       private function getJsonData($methodName) {
          $params = [
             'wstoken' => $this->token,
             'wsfunction' => $methodName, 
             'moodlewsrestformat' => 'json'
          ];
          $url = $this->url . '?' . http_build_query($params);
    
          $ch = curl_init($url);
          if ($ch === FALSE) {
             // Hier Fehler loggen oder anderweit bekanntgeben.
             return null;
          }
    
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
          $response = curl_exec($ch);
          curl_close($ch);
    
          return json_decode($response, true);
       }
    }
    

    Ich habe das jetzt ungetestet runtergetippt, keine Garantie gegen Blödheitsfehler.

    curl_setopt für die URL braucht man jedenfalls nicht, die kann man direkt an init übergeben.

    Ich habe die Parameter-Erstellung, den Curl-Zugriff und die JSON-Dekodierung in eine Methode gesteckt. Das ist nicht unbedingt sinnvoll so. Es hängt davon ab, wie Du die Dinge kombinieren musst. Wenn jeder API Aufruf einen Parameter aus Token, Function und Format erwartet und immer JSON zurückgibt, kann man das so kombinieren. Andernfalls müsste man die Methoden stärker aufgliedern - vermutlich braucht es dann eine flexiblere Erstellung des Parameterarrays. Da kann ich Dir nur Rat geben, wenn ich mehr Methoden von Dir kenne. Wenn Du auch Dinge an Moodle POSTen willst, sieht ja auch der CURL anders aus, dann brauchst Du für Curl-Post eine eigene Methode.

    Jedenfalls sollten am Ende alle Moodle-Zugriffe in dieser Klasse gebündelt sein, so dass $token und $url sonst nirgends mehr gebraucht werden.

    Die Verwendung (Annahme: Klasse steht in moodle.class.php) sähe so aus:

    require_once("moodle.class.php");
    
    $moodle = new Moodle("https://mein.moodle.de");
    $moodle->getToken("blub");   // Was auch immer Du brauchst, um ein Token zu bekommen
    
    $courses = $moodle->getCourses();
    

    Rolf

    --
    sumpsi - posui - obstruxi