<?php

	/*
	* Global variable which is in use by the evaluator errorhandler.
	*/
  $debugConsole_errors = array();
		
	/*
	* Implements the menu hook.
	*/	
  function DebugConsole_menu (){
    
    $items['admin/debugconsole'] = array(
      'title'                   => t('Debug console'), 
    		  'page callback'       => 'drupal_get_form', 
    		  'page arguments'      => array('DebugConsole_form'), 
    		  'access arguments'    => array('administer users'), 
    );
    
  
    return $items;
  }
  
	/*
	* Implements the form hook for console input/output.
	*/	
  function DebugConsole_form(){
  
    $latestCode = variable_get ('DebugConsole_latestCode', '');
    $cache      = cache_get ('DebugConsole');
    $cachedData = '';      
    
    
    
    if (! (empty ($cache->data) && $cache->expire > time ()))
    {
      $cachedData = $cache->data;      
    }
    
    
    
    $form = array ();
    
    $form['output'] = array(
        '#type'         => 'fieldset', 
        '#title'        => t('Output'), 
        '#tree'         => true, 
    );
    
    $form['output']['debug_out'] = array(
        '#type'             => 'item', 
        '#value'            => $cachedData,
    );
    
    $form['input'] = array(
        '#type'         => 'fieldset', 
        '#title'        => t('Input'), 
        '#tree'         => true, 
    );
    
    $form['input']['debug_in'] = array(
        '#type'             => 'textarea', 
        '#description'      => t('Enter PHP code (without php tags). Then hit the "Evaluate" button.<br /><strong>Handle this function with care! Wrong handling could destroy your installation, and it is a high security risk.</strong><br />Parser errors will not displayed!'), 
        '#rows'             => 10, 
        '#default_value'    => '',
        '#attributes'       => array ('style'=>
        'background-color: black; 
         font-weight: bold;
         color: white; 
         font-family: monospace; 
         font-size: 11px;
         padding: 5px;
         border: 2px solid #dddddd;
        ')
    );
    
    
    $form['input']['submit'] = array(
        '#type'     => 'submit', 
        '#value'    => t('Evaluate'), 
    );
    
    $form['latestcode'] = array(
        '#type'         => 'fieldset', 
        '#tree'         => true,
        '#collabsible'  => true,
        '#collapsed'    => true
    );
     
    $form['latestcode']['output'] = array(
        '#type'     => 'item', 
        '#value'    => highlight_string ("<?php\n" . $latestCode . "\n?>", true)
    );
    
    $form['copyright'] = array(
        '#type'         => 'fieldset', 
        '#tree'         => true, 
    );
    
    $form['copyright']['out'] = array(
        '#type'             => 'item', 
        '#value'            => t('2011 &copy; By Marc Sven Rudolf aka Hroudtwolf.<br />All rights reserved.<br /><strong>Use this software at your own risk!</strong>')
    );
        
    // Flushing console output cache.
    cache_set ('DebugConsole', '', 'cache', CACHE_PERMANENT);
    
    return $form;
  }
	
	/*
	* Implements the submit hook for the console form.
	*/  
  function DebugConsole_form_submit($form, &$form_state){
  
    $input  = $form_state['values']['input']['debug_in'];
    $output = _DebugConsole_eval ($input);

    // Caching permanently.
    cache_set ('DebugConsole', $output, 'cache', CACHE_PERMANENT);
    
    // Saving staticely to var table.
    variable_set ('DebugConsole_latestCode', $input);
    
    return;
  }

	/*
	* Implements the errorhandler which is needed by _DebugConsole_eval.
	*/	
  function _DebugConsole_errorHandler($errno, $errstr){
    global $debugConsole_errors;
    
    $debugConsole_errors[] = array("errno"=>$errno, "errstr"=>$errstr);
    
    return;
  }

	/*
	* Implements a PHP evualator which is able to catch all outputs and errors.
	*/  
  function _DebugConsole_eval ($code){
    global $debugConsole_errors;
    
    $debugConsole_errors = array();
  		
    ob_start ();

    set_error_handler('_DebugConsole_errorHandler');
    
    // Starts stopping runtime.
		$runtime = microtime ();
    
    // Safety eval.
		try
    {
      if (_DebugConsole_checkSyntax($code))
      {
         // Safer.
        @eval($code);
      }else{
        // Condome exploded. But girl had luck.
        $debugConsole_errors[] ['errstr'] = "Syntax error.\n<pre style=\"background-color: black; color: white; border: 1px solid gray; padding: 5px;\">" . $code . '</pre>';
      }
    }catch (Exception $e){}
    
    restore_error_handler();
    
    $output = nl2br(ob_get_contents());
    
    ob_end_clean();
    
		$runtime = microtime () - intval ($runtime);
		
    if (! empty ($debugConsole_errors))
    {
      $output .= "\n\n<div class=\"messages error\">" . nl2br($debugConsole_errors [0]['errstr']) . '</div>';
    }else{
			$output .= "\n\n<div class=\"messages information\">Runtime in ms: " . $runtime . '</div>';
    }
    
    return $output;
  }
  
	/*
	* Implements a PHP syntax check.
	*/
  function _DebugConsole_checkSyntax($code){
  
    // Its a little trick.
    // Eval returns FALSE on error.
  
    return @eval('return true;' . $code); 
  }
	
	