== Calling Sage from Other Applications ==

Sage can be started and controlled via a pseudo-tty in the same way Sage calls and makes use of many of it's components. However, an even easier way to use Sage as a backend computational engine is to use the builtin simple server. This simple server can be called from any program that can make HTTP requests. There is self-contained example at [[http://hg.sagemath.org/sage-main/file/tip/sage/server/simple/twist.py|the top of the file]], and an example using PHP is below. 

=== Start the Server ===

First we need to start up a Sage notebook server process. There are many ways to do this, but for a self-contained server (that doesn't interfere with your personal notebook, cleans itself up on disposal, and has a single randomly-crated account) create the file {{{serve.py}}}

{{{
import time, os, random

from sage.server.misc import find_next_available_port
from sage.server.notebook.notebook_object import test_notebook
port = find_next_available_port(9000, verbose=False)
passwd = hex(random.randint(1,1<<128))

f = open('notebook_info.txt', 'w')

# create a new, empty notebook with a single user
nb = test_notebook(passwd, secure=False, address='localhost', port=port, verbose=True)

f.write("%s\n%s\n" % (port, passwd))
f.close()

print "Press control-C to stop."

try:
    # wait until a ^C
    while True:
        time.sleep(10)
except KeyboardInterrupt:
    pass

print "Killing notebook."
nb.dispose()
}}} 

And the server can be started with 

{{{
$ sage -python serve.py
}}}

Upon running this command, the configuration (port and temporary password) will be written to {{{notebook_info.txt}}}. Change the {{{address}}} flag to something other than localhost if you wish to use it from a separate computer. 

=== Use the Server ===

Sage is now ready to be used from another process, either locally or remotely. The following is a very simple PHP script to interface with Sage.

{{{
<?php

$sage_divider = "___S_A_G_E___";

if (isset($_REQUEST['sage_session']) and $_REQUEST['sage_session']) {
    $sage_session = $_REQUEST['sage_session'];
}


if (!isset($json_decode)) {
    
    function _unwrap($s) {
        $s = trim($s);
        if ($s[0] == '"') {
            return substr($s, 1, -1);
        }
        else if ($s[0] == '[') {
            // assumes no comma in items
            $s = trim(substr($s, 1,-1));
            if ($s == "") {
                return array();
            }
            else if (strpos($s, ',') === FALSE) {
                return array(_unwrap($s));
            }
            $all = explode(',', substr($s, 1,-1));
            for($i=0; $i<count($all); $i++) {
                $all[$i] = _unwrap($all[$i]);
            }
            return $all;
        }
        else {
            return intval($s);
        }
    }
    
    function json_decode($s, $assoc=1) {
        // just enough to parse the sage return results...
        $res = array();
        $s = trim($s);
        $s = substr($s, 1, -1); // the outside {}'s
        $all = explode(':', $s);  // can't split on ,'s
        $key = $all[0];
        for($i=1; $i < count($all)-1; $i++) {
            $comma = strrpos($all[$i], ',');
            $val = substr($all[$i], 0, $comma);
            $res[$key] = $val;
            $key = substr($all[$i], $comma+1);
        }
        $res[$key] = $all[count($all)-1];
        // now process the items
        $res2 = array();
        foreach($res as $key => $val) {
            $res2[_unwrap($key)] = _unwrap($val);
        }
        return $res2;
    }
}


function sage_login($server, $username, $password, $renew=0) {
    global $sage_session, $sage_url, $sage_divider;
    $sage_url = $server;
    $page = file_get_contents("$sage_url/simple/login?username=$username&password=$password");
    $res_array = explode($sage_divider, $page);
    $res = json_decode($res_array[0]);
    $sage_session = $res['session'];
    return $sage_session;
}

function sage_eval($line) {
    global $sage_session, $sage_url, $sage_divider;
    $page = file_get_contents("$sage_url/simple/compute?session=$sage_session&code=".urlencode($line));
    $res_array = explode($sage_divider, $page);
    $res = json_decode($res_array[0]);
    $res['result'] = $res_array[1];
    return $res;
}

function sage_readfile($cell, $file) {
    global $sage_session, $sage_url;
    readfile("$sage_url/simple/file?session=$sage_session&cell=$cell&file=$file");
}

function sage_logout() {
    global $sage_session, $sage_url;
    file_get_contents("$sage_url/simple/logout?session=$sage_session");
}

function sage_create_integer($val, $name=NULL) {
    return sage_create_generic("ZZ", $val, $name);
}

function sage_create_rational($val, $name=NULL) {
    return sage_create_generic("QQ", $val, $name);
}

function sage_create_real($val, $name=NULL) {
    return sage_create_generic("RealNumber", $val, $name);
}

function sage_create_expression($val, $name=NULL) {
    return sage_create_generic("SR", $val, $name);
}

$sage_name_counter = 0;

function sage_create_generic($parent, $val, $name=NULL) {
    global $sage_name_counter;
    if ($name == NULL) {
        $sage_name_counter += 1;
        $name = "_php_sage_$sage_name_counter";
    }
    sage_eval("$name = $parent('''" . addslashes($val) . "''')");
    return $name;
}

?>
}}}

Now for a simple example which takes a function and plots and differentiates it. 

{{{
<?php

include "sage.php";

// You could hard-code these...
$data = explode("\n", file_get_contents("notebook_info.txt", "r"));
$pass = $data[1];
$port = $data[0];
$server = "http://localhost:$port";

if (!isset($sage_session) || !$sage_session) {
    sage_login($server, "admin", $pass);
}
else {
    $sage_url = $server;
}



if (isset($_REQUEST['file'])) {
    sage_readfile($_REQUEST['cell'], $_REQUEST['file']);
}
else {
    
?>

<html>
<body>
<?php

if (isset($_REQUEST['expr'])) {

    $f = sage_create_expression($_REQUEST['expr']);
    $res = sage_eval("$f.diff(x)");
    $df = $res['result'];
    $res = sage_eval("plot($f, (x, -5, 5))");
    $plot = $res['files'][0];
    $cell = $res['cell_id'];

//    sage_logout();
    
    echo "f(x) = $_REQUEST[expr]<br>\n";
    echo "df/dx = $df\n<br><br>\n";
    echo "<img src='diff.php?cell=$cell&file=$plot&sage_session=$sage_session'>\n";

    $f_str = $_REQUEST['expr'];
    
    echo "<hr>";
    
}
else {
    $f_str = "";
}


echo "<form>\n";
if (isset($sage_session)) {
    echo "<input type='hidden' name='sage_session' value='$sage_session'>\n";
}
echo "f(x) = <input type='text' name='expr' value='$f_str'>\n";
echo "<input type='submit'>";
echo "</form>\n";

?>
</html>


<?php } ?>
}}}

Put these two files into your web directory, and hard code the password and/or path to {{{notebook_info.txt}}} from above, and it is ready to use. (It takes a bit to start up a new sage session the first time it is accessed.) Note that the user input is ''not'' directly passed to Sage, as this would be a huge security risk. In contrast {{{sage_create_*}}} functions above are safe, as they do not use Python's {{{eval}}}. 

This is just the tip of the iceburg, and can easily be translated to other languages such as Java, C, etc. If timeout it set to values other than -1 long-running computations can be started and later queried/interrupted. Images and other files can be served up directly, and all of Sage is at your disposal.