1<?php 2/** 3 * Virtual machine PNG screenshot generation 4 * 5 * @author Ian Moore (imoore76 at yahoo dot com) 6 * @copyright Copyright (C) 2010-2015 Ian Moore (imoore76 at yahoo dot com) 7 * @version $Id: screen.php 591 2015-04-11 22:40:47Z imoore76 $ 8 * @package phpVirtualBox 9 * 10 */ 11 12# Turn off PHP notices 13error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_WARNING); 14 15require_once(dirname(__FILE__).'/lib/config.php'); 16require_once(dirname(__FILE__).'/lib/utils.php'); 17require_once(dirname(__FILE__).'/lib/vboxconnector.php'); 18 19 20// Allow caching of some screenshot data 21@Header('ETag: "' . $_REQUEST['vm'].'_'.$_REQUEST['randid'].'"'); 22session_cache_limiter('private_no_expire'); 23 24// Check for valid session 25global $_SESSION; 26session_init(); 27if(!@$_SESSION['valid']) { 28 return; 29} 30 31// Clean request 32$_REQUEST = array_merge(@$_GET,@$_POST); 33 34$settings = new phpVBoxConfigClass(); 35$vbox = new vboxconnector(); 36$vbox->connect(); 37 38// Set width. Else assume we want real time updates if VM is running below 39if($_REQUEST['width']) { 40 $force_width = $_REQUEST['width']; 41} 42 43try { 44 45 // Is VM Specified 46 if(!$_REQUEST['vm']) { 47 echo("Please specify a VM to take a screen shot of. E.g. http://webserver/phpvirtualbox/screen.php?vm=VMName"); 48 exit; 49 } 50 51 $machine = $vbox->vbox->findMachine($_REQUEST['vm']); 52 53 // Is snapshot specified? 54 if($_REQUEST['snapshot']) { 55 56 $snapshot = $machine->findSnapshot($_REQUEST['snapshot']); 57 $machine->releaseRemote(); 58 $machine = &$snapshot->machine; 59 60 } else { 61 62 // Get machine state 63 switch($machine->state->__toString()) { 64 case 'Running': 65 case 'Saved': 66 case 'Restoring': 67 break; 68 default: 69 $machine->releaseRemote(); 70 throw new Exception('The specified virtual machine is not in a Running state.'); 71 } 72 73 } 74 75 // Date last modified 76 $dlm = floor($machine->lastStateChange/1000); 77 78 // Set last modified header 79 header("Last-Modified: " . gmdate("D, d M Y H:i:s", $dlm) . " GMT"); 80 81 $_REQUEST['vm'] = $machine->id; 82 83 84 85 // Take active screenshot if machine is running 86 if(!$_REQUEST['snapshot'] && $machine->state->__toString() == 'Running') { 87 88 // Let the browser cache images for 3 seconds 89 $ctime = 0; 90 if(strpos($_SERVER['HTTP_IF_NONE_MATCH'],'_')) { 91 $ctime = preg_replace("/.*_/",str_replace('"','',$_SERVER['HTTP_IF_NONE_MATCH'])); 92 } else if(strpos($_ENV['HTTP_IF_NONE_MATCH'],'_')) { 93 $ctime = preg_replace("/.*_/",str_replace('"','',$_ENV['HTTP_IF_NONE_MATCH'])); 94 } else if(strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'],'GMT')) { 95 $ctime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); 96 } else if(strpos($_ENV['HTTP_IF_MODIFIED_SINCE'],'GMT')) { 97 $ctime = strtotime($_ENV['HTTP_IF_MODIFIED_SINCE']); 98 } 99 100 if($ctime >= (time()-3)) { 101 if (strpos(strtolower(php_sapi_name()),'cgi') !== false) { 102 Header("Status: 304 Not Modified"); 103 } else { 104 Header("HTTP/1.0 304 Not Modified"); 105 } 106 exit; 107 } 108 109 110 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 111 112 $vbox->session = $vbox->websessionManager->getSessionObject($vbox->vbox->handle); 113 $machine->lockMachine($vbox->session->handle,'Shared'); 114 $machine->releaseRemote(); 115 116 117 $res = $vbox->session->console->display->getScreenResolution(0); 118 119 $screenWidth = array_shift($res); 120 $screenHeight = array_shift($res); 121 122 123 // Force screenshot width while maintaining aspect ratio 124 if($force_width) { 125 126 $factor = (float)$force_width / (float)$screenWidth; 127 128 $screenWidth = $force_width; 129 if($factor > 0) { 130 $screenHeight = $factor * $screenHeight; 131 } else { 132 $screenHeight = ($screenWidth * 9.0/16.0); 133 } 134 135 // If no width is set, we were reached from Open in New Window 136 } else if(!$_REQUEST['width']) { 137 138 //Set no caching 139 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); 140 header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); 141 header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); 142 143 } 144 145 // If we were unable to get screen dimensions, set it to something 146 if(!$screenWidth || !$screenHeight) { 147 $screenWidth = 640; 148 $screenHeight = 480; 149 } 150 // array() for compatibility with readSavedScreenshotPNGToArray return value 151 try { 152 $imageraw = array($vbox->session->console->display->takeScreenShotToArray(0, $screenWidth, $screenHeight, 'PNG')); 153 } catch (Exception $e) { 154 // For some reason this is required or you get "Could not take a screenshot (VERR_TRY_AGAIN)" in some cases. 155 // I think it's a bug in the Linux guest additions, but cannot prove it. 156 $vbox->session->console->display->invalidateAndUpdate(); 157 $imageraw = array($vbox->session->console->display->takeScreenShotToArray(0, $screenWidth, $screenHeight, 'PNG')); 158 } 159 160 $vbox->session->unlockMachine(); 161 $vbox->session->releaseRemote(); 162 163 } else { 164 165 // Let the browser cache saved state images 166 $ctime = 0; 167 if(strpos($_SERVER['HTTP_IF_NONE_MATCH'],'_')) { 168 $ctime = preg_replace("/.*_/",str_replace('"','',$_SERVER['HTTP_IF_NONE_MATCH'])); 169 } else if(strpos($_ENV['HTTP_IF_NONE_MATCH'],'_')) { 170 $ctime = preg_replace("/.*_/",str_replace('"','',$_ENV['HTTP_IF_NONE_MATCH'])); 171 } else if(strpos($_SERVER['HTTP_IF_MODIFIED_SINCE'],'GMT')) { 172 $ctime = strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']); 173 } else if(strpos($_ENV['HTTP_IF_MODIFIED_SINCE'],'GMT')) { 174 $ctime = strtotime($_ENV['HTTP_IF_MODIFIED_SINCE']); 175 } 176 177 if($dlm <= $ctime) { 178 if (strpos(strtolower(php_sapi_name()),'cgi') !== false) { 179 Header("Status: 304 Not Modified"); 180 } else { 181 Header("HTTP/1.0 304 Not Modified"); 182 } 183 exit; 184 } 185 186 187 if($_REQUEST['full']) $imageraw = $machine->readSavedScreenshotPNGToArray(0); 188 else $imageraw = $machine->readSavedThumbnailToArray(0, 'PNG'); 189 190 $machine->releaseRemote(); 191 192 } 193 $vbox->session = null; 194 195 header("Content-type: image/png",true); 196 197 foreach($imageraw as $i) { 198 if(is_array($i)) echo(base64_decode($i[0])); 199 } 200 201 202} catch (Exception $ex) { 203 204 // Ensure we close the VM Session if we hit a error, ensure we don't have a aborted VM 205 if($vbox && $vbox->session && $vbox->session->handle) { 206 try { 207 $vbox->session->unlockMachine(); 208 unset($vbox->session); 209 } catch (Exception $e) { 210 } 211 } 212 213 if($_REQUEST['full'] && strpos($ex->faultstring,'VERR_NOT_SUPPORTED') > 0) { 214 @header("Content-type: text/html"); 215 echo("Screen shots are not supported by your VirtualBox installation. To enable screen shots, please install a VirtualBox exteionsion pack that supports VRDE "); 216 echo("such as the Oracle VM VirtualBox Extension Pack found in the Downloads section of <a href='http://www.virtualbox.org'>http://www.virtualbox.org</a>."); 217 } else if($_REQUEST['full'] || $_REQUEST['debug']) { 218 header("Content-type: text/html", true); 219 echo("<pre>"); 220 print_r($ex); 221 echo("</pre>"); 222 } 223} 224 225