Downloading images from the Renderer plugin programmatically

I’ve been trying to download the images (for the purpose of email automation) but grafana keeps rejecting my requests. I’ve used code to download the image URL using the cookie from logging in, to no avail. So I’ve switched to the official API, but there’s no documentation on using the renderer via the API.

How can I download these images? I have my username/password, as well as an API key

if(!function_exists("http_parse_cookie")){
	function http_parse_cookie( $line ) {
		$cookies = array();
		$line = preg_replace( '/^Set-Cookie: /i', '', trim( $line ) );
		$csplit = explode( ';', $line );
		$cdata = array();
		foreach( $csplit as $data ) {
			$cinfo = explode( '=', $data );
			$cinfo[0] = trim( $cinfo[0] );
			if(!isset($cinfo[1])){
				$cinfo[1] = "";
			}
			$cookies[ $cinfo[0] ] = $cinfo[1];
		}
		return $cookies;
	}
}

function parseHeaders( $headers ){
	$head = array();
	foreach( $headers as $k=>$v )    {
		$t = explode( ':', $v, 2 );
		if( isset( $t[1] ) ){
			$t[0] = strtolower( trim($t[0]) );
			$t[1] = trim($t[1]);
			if($t[0] == "set-cookie"){
				if(!isset($head[$t[0]])){
					$head[$t[0]] = [];
				}
				$t[1] = (array) http_parse_cookie($t[1]);
				$head[$t[0]] = array_merge($head[$t[0]], $t[1] );
			} else if(isset($head[ $t[0] ]) && $head[ $t[0] ] != $t[1]){
				if(!is_array($head[ $t[0] ])){
					$head[ $t[0] ] = [$head[ $t[0] ]];
				}
				$head[ $t[0] ][] = $t[1];
			} else {
				$head[ $t[0] ] = $t[1];
			}
		} else{
			if( preg_match( "#HTTP/[0-9\.]+\s+([0-9]+)#", $v, $out ) ){
				$head['reponse_code'] = intval($out[1]);
				$v = explode(" ", $v);
			}
			$head[] = $v;
		}
	}
	return $head;
}

function file_post_contents($URL, $POST = false, $COOKIE = false, $contenttype = "application/x-www-form-urlencoded", $built = true, $redirects = true){
	if($built){
		if(!$POST){
			$POST				= [];
		}
		$POST					= http_build_query($POST);
	}
	$URL 						= str_replace(" ", "%20", $URL);
	$opts = array('http' => array(
			'method' 			=> 'POST',
			'header'  			=> [
				'Content-Type' 	=> $contenttype,
				'Accept'		=> 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
				'User-Agent'	=> 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
				'Authorization'	=> 'Bearer ' . grafana_api_key,
			],
	));
	if($POST){
		$opts["http"]["content"] = $POST;
	}
	if($COOKIE){
		$opts["http"]["header"]["Cookie"] = $COOKIE;
	}
	
	foreach($opts["http"]["header"] as $key => $value){
		$opts["http"]["header"][$key] = $key . ": " . $value;
	}
	$opts["http"]["header"]		= implode("\r\n", $opts["http"]["header"]);		
	$context  					= stream_context_create($opts);
	try {
		$data					= file_get_contents($URL, false, $context);
	} catch (Exception $e) {
		echo 					$e->getMessage();
		$data 					= false;
	}
	if($data === false){
		var_dump($opts);
		die($URL . " DID NOT DOWNLOAD");
	} else {
		$HEADER					= parseHeaders($http_response_header);		
		if($redirects && $HEADER[0][1] == 302 && isset($HEADER["set-cookie"]["redirect_to"])){
			$URL 				= array_merge(["URL" => $URL], parse_url($URL));
			$URL["folder"]		= $HEADER["set-cookie"]["redirect_to"];
			$URL["redirect"]	= $URL["scheme"] . "://" . $URL["host"] . ":" . $URL["port"] . urldecode($URL["folder"]);
			if($URL["redirect"] != $URL["URL"]){
				//$data 		= file_post_contents($URL["redirect"], $POST, $COOKIE, $contenttype, false, false);
				var_dump($data);
				die("REDIRECT: " . $URL);
			}
		}
		$data						= array_merge(["DATA" => $data, "REQUEST" => $opts], $HEADER);
	}
	return $data;
}

function grafana($panelID = 2, $start = "1615492536959", $end = "1615514136959", $width = 1000, $height = 500, $filename = "grafana.png"){
	$BASEURL = grafana_url;
	ini_set('max_execution_time', 0);
	if(!isset($GLOBALS["grafana"])){
		$COOKIE = file_post_contents($BASEURL . "login", ["user" => grafana_username, "password" => grafana_password]);
		if(isset($COOKIE["set-cookie"])){
			if(isset($COOKIE["set-cookie"]["grafana_session"])){
				$GLOBALS["grafana"] = $COOKIE["set-cookie"]["grafana_session"];
			}
		}
	}
	if(!isset($GLOBALS["grafana"])){
		die("Unable to log in");
	}
	
	$URL = $BASEURL . "render/d-solo/7iMeja8Mz/vendor-staffing-compliance?orgId=1&from=" . $start . "&to=" . $end . "&panelId=" . $panelID;
	$URL .= "&width=" . $width . "&height=" . $height . "&tz=America%2FToronto";
	
	$opts = ["http" => [
		"method" => "GET",
		"header" => "Host: nunabiz.nes
Connection: keep-alive
Cache-Control: max-age=0
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: grafana_session=" . $GLOBALS["grafana"] . "
If-Modified-Since: Fri, 12 Mar 2021 03:27:27 GMT",
	]];
	$IMG = file_get_contents($URL, false, stream_context_create($opts));
	$FIL = public_path($filename);
	file_put_contents($FIL, $IMG);
	
	return [
		"html" 		=> '<IMG SRC="/public/' . $filename . '">',
		"url" 		=> '/public/' . $filename,
		"filename" 	=> $FIL,
	];
}

I was able to get image downloading working, but it takes 2 minutes an image! Am I doing something wrong or is that normal?

Did follow memory requirements? Image rendering | Grafana Labs

I’m getting a really low peak usage, but downloading the images myself doesn’t take 2 minutes. Why would file_get_contents take that long?

Seems to have been a problem with how PHP downloaded files, I switched from file_get_contents to cURL and it now takes less than 10 seconds.

I hope my code comes in handy for someone. file_post_contents, http_parse_cookie and parseHeaders are overkill, but I prefer to make reusable/universal code. You probably don’t need the API key either.

Switch this line:
$IMG = file_get_contents($URL, false, stream_context_create($opts));
To:
$IMG = download($URL, $opts);

And add this:

	function download($URL, $options, $method = 1){
	switch($method){
		case 0://file_get_contents
			return file_get_contents($URL, false, stream_context_create($options));
		case 1://cURL
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $URL);
			//curl_setopt($ch, CURLOPT_POST, 1);
			//curl_setopt($ch, CURLOPT_POSTFIELDS,$vars);  //Post Fields
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			$headers = explode(PHP_EOL, $options["http"]["header"]);
			foreach($headers as $index => $header){
				$headers[$index] = trim($header);
			}
			curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
			return curl_exec ($ch);
	}
}