Bagi teman-teman penggemar CLI (Command Line Interface), andre nemuin sesuatu yang menarik nih. Yaks yaitu jQuery Terminal, dengan jQuery Terminal Anda para pecinta Command Line bisa membuat Terminal versi Anda sendiri berbasiskan web. Gimana, menarik bukan? Oke langsung saja.

Terminal ala Asong Soekamti

Oke, pertama anda buat file index.php. Isinya seperti berikut ini :

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>Asong Terminal</title>
    <meta name="author" content="Andreas BKH"/>
    <meta name="Description" content="Asong jQuery Terminal"/>
	<link href="https://fbcdn-sphotos-e-a.akamaihd.net/hphotos-ak-ash4/483487_575244042491760_820527717_n.jpg" rel="icon" type="image/x-icon" />
    <script src="js/jquery-1.7.1.min.js"></script>
    <script src="js/jquery.mousewheel-min.js"></script>
    <script src="js/jquery.terminal-min.js"></script>
    <link href="css/jquery.terminal.css" rel="stylesheet"/>
    <script>
    jQuery(document).ready(function($) {
        $('body').terminal("services.php", {
            login: true,
            greetings: "\n-------------------\nAsong Terminal\n-------------------\nThanks to :\n1. Malang Cyber Crew\n2. Devilzc0de\n3. K4mpr3t\n\nfor instruction type help and Enter",
            onBlur: function() {
                return false;
            }
        });
    });
    </script>
  </head>
<body>
</body>

Kemudian anda buat file dengan nama rpc.php

<?php
function json_error() {
  switch (json_last_error()) {
  case JSON_ERROR_NONE:
    return 'No error has occurred';
  case JSON_ERROR_DEPTH:
    return 'The maximum stack depth has been exceeded';
  case JSON_ERROR_CTRL_CHAR:
    return 'Control character error, possibly incorrectly encoded';
  case JSON_ERROR_SYNTAX:
    return 'Syntax error';
  case JSON_ERROR_UTF8:
    return 'Malformed UTF-8 characters, possibly incorrectly encoded';
  }
}

function has_field($object, $field) {
  return array_key_exists($field, get_object_vars($object));
}

function get_field($object, $field, $default) {
  $array = get_object_vars($object);
  if (isset($array[$field])) {
    return $array[$field];
  } else {
    return $default;
  }
}

function response($result, $id, $error) {
  return json_encode(array("jsonrpc" => "2.0",
			   'result' => $result,
			   'id' => $id,
			   'error'=> $error));
}

function extract_id() {
  $regex = '/[\'"]id[\'"] *: *([0-9]*)/';
  if (preg_match($regex, $GLOBALS['HTTP_RAW_POST_DATA'], $m)) {
    return $m[1];
  } else {
    return 0;
  }
}

function handle_json_rpc($object) {

  $input = $GLOBALS['HTTP_RAW_POST_DATA'];
  $encoding = mb_detect_encoding($input, 'auto');

  if ($encoding != 'UTF-8') {
    $input = iconv($encoding, 'UTF-8', $input);
  }
  $input = json_decode($input);
  header('Content-Type: text/plain');

  if (!$input) {
    if ($GLOBALS['HTTP_RAW_POST_DATA'] == "") {
      echo response(null, 0, array("code"=> -32700,
				   "message"=>"Parse Error: no data"));
    } else {

      $error = json_error();
      $id = extract_id();
      echo response(null, $id, array("code"=> -32700,
				     "message"=>"Parse Error: $error"));
    }
    exit;
  } else {
    $method = get_field($input, 'method', null);
    $params = get_field($input, 'params', null);
    $id = get_field($input, 'id', null);

    if (!($method && $id)) {
      if (!$id) {
        $id = extract_id();
      }
      if (!$method) {
	    $error = "no method";
      } else if (!$id) {
	    $error = "no id";
      } else {
	    $error = "unknown reason";
      }
      echo response(null, $id, array("code" => -32600,
				     "message" => "Invalid Request: $error"));
      exit;
    }
  }

  if (!$params) {
    $params = array();
  }

  if (is_object($params)) {
    if (count(get_object_vars($params)) == 0) {
      $params = array();
    } else {
      $params = get_object_vars($params);
    }
  }

  try {
    $class = get_class($object);
    $methods = get_class_methods($class);
    if (strcmp($method, 'help') == 0) {
      if (count($params) > 0) {
        if (!in_array($params[0], $methods)) {
          $no_method = 'There is no ' . $params[0] . ' method';
          throw new Exception($no_method);
        } else {
          $static = get_class_vars($class);
          $help_str_name = $params[0] . "_documentation";

          if (array_key_exists($help_str_name, $static)) {
            echo response($static[$help_str_name], $id, null);
          } else {
            throw new Exception($method . " method has no documentation");
          }
        }
      } else {
        $url = "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
        $msg = "\n----------------\nAsong Terminal\n----------------\n";
        $msg .= "User \"$class\" has methods: " . implode(", ", array_slice($methods, 0, -1)) . " and " .  $methods[count($methods)-1] . "." . "\n";
        echo response($msg, $id, null);
      }
    } else if (!in_array($method, $methods)) {
      $msg = 'There is no ' . $method . ' method';
      echo response(null, $id, array("code" =>-32601, "message" => $msg));
    } else {

      $result = call_user_func_array(array($object, $method), $params);
      echo response($result, $id, null);
    }
    exit;
  } catch (Exception $e) {

    $msg = "Internal error: " . $e->getMessage();
    echo response(null, $id, array("code"=>-32603, "message"=>$msg));
  }
}
?>

Selanjutnya anda buat file dengan nama services.php

<?php
error_reporting(0);
require('rpc.php');

if(function_exists('xdebug_disable')) { xdebug_disable(); }

class admin {
  static $login_documentation = "login to the server (return token)";
  public function login($user, $passwd) {
    if (strcmp($user, 'admin') == 0 && strcmp($passwd, 'password') == 0) {
      return md5($user . ":" . $passwd);
    } else {
      throw new Exception("Wrong Password");
    }
  }

  static $ls_documentation = "list directory if token is valid";
  public function ls($token, $path = null) {
    if (strcmp(md5("admin:password"), $token) == 0) {
      if (preg_match("/\.\./", $path)) {
        throw new Exception("No directory traversal Dude");
      }
      $base = preg_replace("/(.*\/).*/", "$1", $_SERVER["SCRIPT_FILENAME"]);
      $path = $base . ($path[0] != '/' ? "/" : "") . $path;
      $dir = opendir($path);
      while($name = readdir($dir)) {
        $fname = $path."/".$name;
        if (!is_dir($name) && !is_dir($fname)) {
          $list[] = $name;
        }
      }
      closedir($dir);
      return $list;
    } else {
      throw new Exception("Access Denied");
    }
  }
  static $whoami_documentation = "return user information";
  public function whoami() {
    return array("your User Agent" => $_SERVER["HTTP_USER_AGENT"],
                 "your IP" => $_SERVER['REMOTE_ADDR']);
  }

}

handle_json_rpc(new admin());

?>

Kemudian anda buat folder dengan nama folder css dan buat file dengan nama jquery.terminal.css

.terminal .terminal-output .format, .terminal .cmd .format,
.terminal .cmd .prompt, .terminal .cmd .prompt div, .terminal .terminal-output div div{
    display: inline-block;
}
.terminal .clipboard {
    position: absolute;
    bottom: 0;
    left: 0;
    opacity: 0.01;
    filter: alpha(opacity = 0.01);
    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0.01);
    width: 2px;
}
.cmd > .clipboard {
    position: fixed;
}
.terminal {
    padding: 10px;
    position: relative;
    overflow: hidden;
}
.cmd {
    padding: 0;
    margin: 0;
    height: 1.3em;
    /*margin-top: 3px; */
}
.terminal .terminal-output div div, .terminal .prompt {
    display: block;
    line-height: 14px;
    height: auto;
}
.terminal .prompt {
    float: left;
}

.terminal {
    font-family: FreeMono, monospace;
    color: #aaa;
    background-color: #000;
    font-size: 12px;
    line-height: 14px;
}
.terminal-output > div {
    /*padding-top: 3px;*/
}
.terminal .terminal-output div span {
    display: inline-block;
}
.terminal .cmd span {
    float: left;
    /*display: inline-block; */
}
.terminal .cmd span.inverted {
    background-color: #aaa;
    color: #000;
}
.terminal .terminal-output div div::-moz-selection,
.terminal .terminal-output div span::-moz-selection,
.terminal .terminal-output div div a::-moz-selection {
    background-color: #aaa;
    color: #000;
}
.terminal .terminal-output div div::selection,
.terminal .terminal-output div div a::selection,
.terminal .terminal-output div span::selection,
.terminal .cmd > span::selection,
.terminal .prompt span::selection {
    background-color: #aaa;
    color: #000;
}
.terminal .terminal-output div.error, .terminal .terminal-output div.error div {
    color: red;
}
.tilda {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 1100;
}
.clear {
    clear: both;
}
.terminal a {
    color: #0F60FF;
}
.terminal a:hover {
    color: red;
}

Untuk jQuery nya, anda bisa download file ini : http://www.mediafire.com/?ppo0hrs53z1cabw kemudian ekstrak.

Untuk DEMOnya bisa anda lihat disini : http://andreas-bkh.net/demo/jQueryTerminal/

login : admin
password : password

untuk mengunduh scriptnya secara lengkap silahkan download disini : http://www.mediafire.com/?3msqao280poep3m

Referensi : http://terminal.jcubic.pl/