How to Call SWI-Prolog from PHP 5

2015.04.28 19:34

졸리운_곰 조회 수:524

 

 

 

 

How to Call SWI-Prolog from PHP 5

 

I have scripts on my Web site that call SWI-Prolog from PHP 5. They run: a game for teaching Prolog, where the players are "intelligent" lorries that survive by buying and selling their freight, and buying petrol with the profit thereby earned; a science-fiction plot generator; and a generator of examples in category theory. A reader saw these last week and asked me why his Prolog-from-PHP script didn't work; so I'm going to explain how to code ones that do. My examples should work, mutatis mutandis, with other Prologs and other languages; and if you program in SWI-Prolog, they'll give you tested code that will get you started straight away.

Contents

Introduction: a simple script

I'll start by showing how to call an SWI-Prolog program from PHP 5 in four different ways. The program itself is as simple as can be, merely defining one predicate named test/0 that writes a sentence to standard output. For most other languages, that's analogous to a subroutine or procedure that does the same. This is the predicate, which writes four lines, newline being escaped as "\n":

test :-
  write( 'Prolog \nwas called \nfrom PHP \nsuccessfully.' ).

 

Next, please follow the link Calling SWI-Prolog from PHP to run the script on my site that calls it. In case the server should be down, here is the business portion of the script's output. It's a table that lists four different sets of PHP statements that invoke a run-SWI-Prolog command stored in the PHP variable $cmd. The statements are on the left and their output is on the right:

  system( $cmd );
Prolog 
was called 
from PHP 
successfully. 
  $output = exec( $cmd );
  echo $output;
successfully. 
  exec( $cmd, $output );
  print_r( $output );
Array
(
    [0] => Prolog
    [1] => was called
    [2] => from PHP
    [3] => successfully.
)
 
  $output = shell_exec( $cmd );
  echo $output;
Prolog 
was called 
from PHP 
successfully. 

And now I'll show the script. Because the one linked above that generated the table has a lot of HTML markup in it, I'm going to show a shortened version, that generates the output you'll see by following the link Calling SWI-Prolog from PHP (short). The full script is in the Appendix. Here is the short one:

<HTML>
< HEAD>
< TITLE>Calling SWI-Prolog from PHP (short)</TITLE>
< /HEAD>

< H1>Calling SWI-Prolog from PHP (short)</H1>

< ?
  $cmd = "nice -n15 /software/bin/pl -f /home/popx/cgi-bin/test.pl -g test,halt";
?>

< P>
< PRE>
< ?
  system( $cmd );
  echo "\n";

  $output = exec( $cmd );
  echo $output;
  echo "\n";

  exec( $cmd, $output );
  print_r( $output );
  echo "\n";

  $output = shell_exec( $cmd );
  echo $output;
  echo "\n";
?>
< /PRE>
< /P>

< /BODY>
< /HTML>

 

I'll assume that you know enough PHP to understand that the script outputs the HTML markup verbatim, and that it executes the statements between "<?" and "?>" tags, sending their output to the server's output stream.

The first of these statements sets the variable $cmd to a Linux command that runs SWI-Prolog on my code. This is the command; all I've done above is to put it in a string by enclosing with quotes:

nice -n15 /software/bin/pl -f /home/popx/cgi-bin/test.pl -g test,halt

 

Be nice with "nice"

A point of etiquette is worth noting next. I could have written this command:

/software/bin/pl -f /home/popx/cgi-bin/test.pl -g test,halt

However, the "nice" reduces its priority, and hence interference with the server's other users. On a multi-user machine — such as mine, which belongs to the excellent hosting company Mythic Beasts — this is polite.

 

The SWI-Prolog command line

The rest of the command runs the SWI-Prolog executable from its home in /software/bin/pl . It passes it the file in which I defined test/0 , using SWI's -f option to read it from /home/popx/cgi-bin/test.pl . The -f , and other SWI command-line options, are described in the section on Command-line options in the SWI-Prolog reference manual.

The command finishes with another option, flagged by -g . The point is that so far, we've told Prolog which source file to load, but not which predicate from that file to run. That's what -g does. It passes the compound goal:

test,halt

which calls test/0 and then executes the built-in halt/0 to end the program.

 

So that is the command to run Prolog. The rest of the script invokes it in four different ways, by calling the PHP functions "system", "exec" (in two ways), and "shell_exec". I'll explain these next, and then discuss their merits.

Calling SWI-Prolog with PHP 5's "system", "exec", and "shell_exec" functions

The "system" function runs the command and sends all its output to standard output. More information can be found from the PHP manual entries for these functions, linked from here.

The one-argument variant of the "exec" function runs the command and returns only the final line of its output as a string.

The two-argument variant of "exec" puts an array into its second argument. Each line is one line of the command's output. In my script, I displayed this array with the built-in print_r.

Finally, the "shell_exec" function runs the command and returns all its output as a string. This function is identical to PHP's backticks operator.

One thing that puzzled me was the difference between shell_exec and the one-argument form of "exec". Others have wondered the same, as a Google search on "difference exec shell_exec" will show. On PHPBuilder.com, contributor "dalecosp" gives code fragments that demonstrate the functions — and also "passthru", used for sending back binary data such as images. He says that shell_exec knows how to find built-in commands such as "ping", implying that "exec" doesn't. However, I tried invoking Linux "ls" with "exec", and it worked.

My search also turned up complaints about bugs in one function or the other. I should say that I have had no problems with PHP 5's "system" or "shell_exec" under Linux, and that I've not used the other functions except in these examples.

Which function should one use?

Given these ways of invoking Prolog, when are they appropriate? The "system" function is useful when you simply want to squirt all your program's output back at the Web browser. I do this in my science-fiction plot generator, as you can see from the source I've put up of its script.

The one-argument "exec" doesn't seem particularly useful, and I included it only to show how it differs from the two-argument variant. The latter is useful for the same reason that shell_exec is, namely that it allows one to manipulate the output rather than just flinging it all into a browser. Such manipulation, for preserving the Prolog program's state between transactions in a session, and for splitting off different chunks of output to display in different regions of the page, is what I'll discuss next, with reference to my Traveller game for teaching Prolog.

Traveller, a game that saves its state

Traveller is about an "intelligent" lorry that drives round a road network on the game board, buying and selling goods at shops along the way. Because the lorry must also buy petrol, and because goods cost money and take up space, which limits carrying capacity, and because different shops charge and pay different prices, brains are needed to earn enough money to survive. Students can thus compete with the environment, and with one another, by trying to program sufficiently clever brains.

The game was originally part of my Logic Programming Tutor, a front-end for Prolog with which I taught my students. There, users advanced lorries from one square to the next by typing an appropriate Prolog goal. On the Web, however, I've connected this goal to the "Next" button. Pressing the button moves a lorry one square, depicting its location in yellow, and also causes it to take whatever buying or selling decision its brain may dictate.

The game needs to preserve state between button presses. Amongst the components of this state are the goods in the lorry, the lorry's position, how much fuel it has, and its cash. So how do I do this without making Prolog save it to a temporary file or a database?

Answer: by making Prolog send the state, as well as the game's output, to standard output. If our script can capture standard output in a PHP variable, we can then split the two apart, emit the game output, and save the rest in PHP's $_SESSION variable.

Session-handling in PHP 5: the $_SESSION array

So what is $_SESSION? It's a built-in PHP array. Like any other PHP array, but unlike arrays in most languages, its indices can be integers or strings. Unlike other PHP arrays, PHP preserves its contents from one Web transaction to the next, making it terribly easy to implement session handling.

I'm not going to explain session handling in detail, but a small example may help. It's one you can run from my page Running a PHP Session. And you can get its source from the section on PHP Sessions: Using PHP's isset Function in Tizag's tutorial PHP Sessions - Why Use Them?, where I copied it from.

It displays a counter that increments every time you reload the page. Tizag accomplish this by storing the counter as $_SESSION['views']. The page tests whether this contains a value, and if so, increments it. This is the code:

<?php
session_start();
if ( isset( $_SESSION['views'] ) )
    $_SESSION['views'] = $_SESSION['views'] + 1;
else
    $_SESSION['views'] = 1;

echo "views = ". $_SESSION['views'];
?>

For more info on sessions and $_SESSION, Google "session handling in PHP $_session".

 

How Traveller saves its state

Returning to the idea of making Prolog write state, as well as game output, to its standard output, this is what my Traveller script, listed here, does. You will see that it contains the following code fragment:

$output = shell_exec($cmd);

// Build the Prolog command and, using shell_exec, get
// the output as a string.

list($english_state,$board,$prolog_state) = split ("==========", $output, 3);
// Split output into an English description of the new
// state, a table displaying the board, and the new
// state.

$_SESSION['game_state'] = $prolog_state;
// Store the latter.

 

There are some statements before this fragment that look the game state up in $_SESSION['game_state'], then build a command to invoke Prolog so that it loads the game program and passes it the state as argument to a goal.

This command is held, as before, in $cmd. The script calls shell_exec($cmd), assigning its output to $output. By looking for the separator "==========" which the game inserts into its output, the script splits this output into three parts, which it assigns to $english_state, $board, and $prolog_state.

The first two variables, $english_state and $board, both get displayed to the user. One lists the lorry's contents, cash, and so on. The other is the game board, complete with road map, shop names, and yellow square marking the lorry's position. These, the script sends back to the browser. There is some static HTML between them, which I wrote verbatim into the script. As I said earlier, capturing program output in a string enables us to reorder parts of it in this way.

The third variable, $prolog_state, gets assigned back to $_SESSION['game_state']. And that completes one cycle, ready for the next run of the script.

A simpler example of saved state

Lest Traveller be too complicated, I'll present a simpler script which you can run as is. It may help you get started with Prolog and sessions, because if you can't run it, something is probably wrong with your setup; but if you can, then you can build more complicated variants by gradually replacing parts of the script and program.

The script emits similar output to the one shown in my section on Session-handling in PHP 5: the $_SESSION array. The difference is that it's Prolog that generates the output, and Prolog that increments the view counter. To try the script, please go to the link Running a PHP Session with Prolog.

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

Next, here is the Prolog predicate it runs. The predicate, in file test2.pl , takes one argument, ViewsSoFar. It displays this plus a small message, then writes an "==========" separator, then increments ViewsSoFar into ViewsNow, which it writes. These pieces of output either side of the "==========" correspond to the game output and game state from Traveller:

test( ViewsSoFar ) :-
  write( 'Prolog \nwas called \nfrom PHP \nsuccessfully.
\n' ),
  format( 'Views = ~w.~n', [ViewsSoFar] ),
  ViewsNow is ViewsSoFar + 1,
  write( '==========\n' ),
  format( '~w~n', [ViewsNow] ).

 

And here is my script:

<HTML>
< HEAD>
< TITLE>Running a PHP Session with Prolog</TITLE>
< /HEAD>

< BODY>

[ <A HREF="/index.html">Jocelyn Ireson-Paine's Home Page</A>
| <A HREF="/dobbs/prolog_from_php.html"><CITE>How to Call SWI-Prolog from
PHP</CITE></A>
]

< CENTER>
< H1>Running a PHP Session with Prolog</H1>
< /CENTER>

< ?
session_start();

if ( isset( $_SESSION['views'] ) ) {

    $views_so_far = $_SESSION['views'];

    $goal = "test($views_so_far)";

    $cmd = "nice -n15 /software/bin/pl -f /home/popx/cgi-bin/test2.pl -g \"$goal,halt\"";

    $output = shell_exec( $cmd );

    list($english_state,$prolog_state) = split ("==========", $output, 2);

    echo $english_state;

    $_SESSION['views'] = $prolog_state;
}
else
    $_SESSION['views'] = 1;

?>
< /P>

< /BODY>
< /HTML>

 

Notice that the script echoes $english_state. This is the output to the browser, as in Traveller. Whilst $prolog_state gets assigned to $_SESSION['views'], updating it and ending the cycle.

Running a pre-compiled SWI-Prolog program

We can increase speed by, in effect, pre-compiling programs in order to avoid reading their source each time the script is called. The SWI-Prolog reference manual explains this in its section on Generating Runtime Applications. The feature is actually more general than pre-compilation, because one can load a program from its source file, let it do introductory calculations such as asserting new predicates, and then save it as a runtime application. Obviously, this avoids not only the time taken to read and compile, but also the time needed for these calculations.

The SWI-Prolog HTTP server libraries

Because my Traveller script starts SWI-Prolog and loads my program into it on every transaction, as well as reading and writing the game state, it is probably less efficient than letting SWI-Prolog run all the time and act as its own Web server. This can in fact be done, and is explained in the SWI-Prolog manual's section about The HTTP server libraries. I haven't used them, because I am running Prolog on a commercial hosting company's machine. But for those who do have the privileges, it's worth trying.

The HTTP server libraries get discussed from time to time on the SWI-Prolog mailing list. Indeed, SWI's author Jan Wielemaker has just sent us a mail recommending his SWI-Prolog how-to on Web services, How to create a web-service easily? It explains how to find information about JSON/XML responses, not yet covered by the how-to.

Appendix: the full script that showed four ways of invoking Prolog

This is the script referred to in the Introduction:

 

<HTML>
< HEAD>
< TITLE>Calling SWI-Prolog from PHP</TITLE>
< /HEAD>

< BODY>

[ <A HREF="/index.html">Jocelyn Ireson-Paine's Home Page</A>
| <A HREF="/dobbs/prolog_from_php.html">How to Call SWI-Prolog from
PHP</A>
]

< CENTER>
< H1>Calling SWI-Prolog from PHP</H1>
< /CENTER>

< ?
  $cmd = "nice -n15 /software/bin/pl -f /home/popx/cgi-bin/test.pl -g test,halt";
?>

< P>
< TABLE BORDER>
< TR>
< TH ALIGN=left>
< PRE>
  system( $cmd );
< /PRE>
< /TH>
< TD ALIGN=left>
< PRE>
< ?
  system( $cmd );
?>
< /PRE>
< /TD>
< /TR>
< TR>
< TH ALIGN=left>
< PRE>
  $output = exec( $cmd );
  echo output;
< /PRE>
< /TH>
< TD ALIGN=left>
< PRE>
< ?
  $output = exec( $cmd );
  echo output;
?>
< /PRE>
< /TD>
< /TR>
< TR>
< TH ALIGN=left>
< PRE>
  exec( $cmd, $output );
  print_r( $output );
< /PRE>
< /TH>
< TD ALIGN=left>
< PRE>
< ?
  exec( $cmd, $output );
  print_r( $output );
?>
< /PRE>
< /TD>
< /TR>
< TR>
< TH ALIGN=left>
< PRE>
  $output = shell_exec( $cmd );
  echo $output;
< /PRE>
< /TH>
< TD ALIGN=left>
< PRE>
< ?
  $output = shell_exec( $cmd );
  echo $output;
?>
< /PRE>
< /TD>
< /TR>
< /TABLE>
< /P>

< /BODY>
< /HTML>

 

Links

www.swi-prolog.org/ — SWI-Prolog.

www.php.net/ — PHP.

www.swi-prolog.org/pldoc/refman/ — SWI-Prolog reference manual.

www.php.net/manual/en/index.php — PHP 5 reference manual.

www.j-paine.org/cgi-bin/spin.php — My science-fiction plot generator.

www.j-paine.org/spin_script.html — Source listing of its script.

www.j-paine.org/cgi-bin/traveller.php — My Traveller game.

www.j-paine.org/traveller_script.html — Source listing of its script.

www.j-paine.org/cgi-bin/webcats/webcats.php — My interactive category-theory demonstrations.

www.j-paine.org/cgi-bin/demo_php_calls.php — My page that demonstrates the PHP "system", "exec", and "shell_exec" functions, listed in the Appendix.

www.j-paine.org/cgi-bin/short_demo_php_calls.php — Short version of the above, listed in the Introduction.

www.swi-prolog.org/pldoc/doc_for?object=section%282%2c%20%272.4%27%2c%20swi%28%27%2fdoc%2fManual%2fcmdline.html%27%29%29 — SWI-Prolog reference manual section on the command line.

php.net/manual/en/function.system.php — PHP reference manual section on the "system" function.

php.net/manual/en/function.exec.php — PHP reference manual section on the "exec" function.

php.net/manual/en/function.shell-exec.php — PHP reference manual section on the "shell_exec" function.

www.php.net/manual/en/language.operators.execution.php — PHP reference manual section on the backticks operator.

www.google.com/search?hl=en&rlz=1B3GGGL_enGB219GB237&q=difference+exec++shell_exec&lr=&aq=f&aqi=&oq= — Google search for "difference exec shell_exec".

www.phpbuilder.com/board/archive/index.php/t-10260187.html — Contributor "dalecosp"'s code fragments demonstrating "system", "exec", "passthru", and "shell_exec".

php.net/manual/en/function.passthru.php — PHP reference manual section on the "passthru" function.

www.php.net/manual/en/reserved.variables.session.php — PHP reference manual section on the $_SESSION array variable.

php.net/manual/en/language.types.array.php — PHP reference manual section on arrays.

www.j-paine.org/cgi-bin/demo_session.php — My page that demonstrates PHP sessions, discussed in the section on Session-handling in PHP 5: the $_SESSION array.

www.tizag.com/phpT/phpsessions.php — Tizag's tutorial on PHP sessions PHP Sessions - Why Use Them?.

www.google.com/search?hl=en&rlz=1B3GGGL_enGB219GB237&q=session+handling+in+PHP+%24_session&lr=&aq=f&aqi=&oq= — Google search for "session handling in PHP $_session".

www.j-paine.org/cgi-bin/demo_session_with_prolog.php — My page that demonstrates PHP sessions with Prolog: the simple one from the section on A simpler example of saved state.

www.swi-prolog.org/pldoc/doc_for?object=section%281%2c%20%2710%27%2c%20swi%28%27%2fdoc%2fManual%2fruntime.html%27%29%29 — SWI-Prolog reference manual section on generating runtime applications.

www.swi-prolog.org/pldoc/doc_for?object=section%282%2c%20%273%27%2c%20swi%28%27%2fdoc%2fpackages%2fhttp.html%27%29%29 — SWI-Prolog reference manual section on the HTTP server libraries.

www.swi-prolog.org/Mailinglist.html — SWI-Prolog mailing list.

www.swi-prolog.org/howto/http/ — SWI-Prolog how-to on Web services, How to create a web-service easily?

mailbox.iai.uni-bonn.de/mailman/public/swi-prolog/2010/003218.html — SWI-Prolog mail about the HTTP server libraries. Explains how to find information on JSON/XML responses.

 

 

 

[출처] http://www.j-paine.org/dobbs/prolog_from_php.html

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
1195 [ 一日30分 인생승리의 학습법] VBA Web Scraping: How Can VBA Be Used To Scrape Website Data? file 졸리운_곰 2024.04.13 3
1194 [ 一日30分 인생승리의 학습법] 윈도우 실행파일 구조(PE파일) file 졸리운_곰 2024.03.31 3
1193 [ 一日30分 인생승리의 학습법] [Analysis] PE(Portable Executable) 파일 포맷 공부 file 졸리운_곰 2024.03.31 3
1192 [ 一日30分 인생승리의 학습법] 성공하는 메타버스의 3가지 조건 file 졸리운_곰 2024.03.30 7
1191 [ 一日30分 인생승리의 학습법] REST, REST API, RESTful 과 HATEOAS file 졸리운_곰 2024.03.10 9
1190 [ 一日30分 인생승리의 학습법] 렌더링 삼형제 CSR, SSR, SSG 이해하기 file 졸리운_곰 2024.03.10 2
1189 [ 一日30分 인생승리의 학습법] 엑셀 VBA에서 셀레니움 사용을 위한 Selenium Basic 설치 file 졸리운_곰 2024.02.23 11
1188 [ 一日30分 인생승리의 학습법]500 Lines or Less Blockcode: A Visual Programming Toolkit : 500줄 이하의 블록코드: 시각적 프로그래밍 툴킷 졸리운_곰 2024.02.12 4
1187 [ 一日30分 인생승리의 학습법] 구글 클라이언트(앱) 아이디를 발급받으려면 어떻게 해야 하나요? 졸리운_곰 2024.01.28 3
1186 [ 一日30分 인생승리의 학습법] 빅뱅 프로젝트를 성공적으로 오픈하기 위한 팁 졸리운_곰 2023.12.27 16
1185 [ 一日30分 인생승리의 학습법]“빅뱅 전환보다 단계적 전환 방식이 이상적 애자일팀과 협업 쉽게 체질 개선을” file 졸리운_곰 2023.12.27 12
1184 [ 一日30分 인생승리의 학습법] Big-bang / phased 접근 file 졸리운_곰 2023.12.27 3
1183 [ 一日30分 인생승리의 학습법] CodeDragon 메뉴 데이터 전환의 개념 이해 - 데이터 전환의 개념, 데이터 전환방식, 데이터 전환방식 및 장단점 비교, 데이터전환 이후 검토해야 할 사항 졸리운_곰 2023.12.27 5
1182 [ 一日30分 인생승리의 학습법] 블록체인과 IPFS를 이용한 안전한 데이터 공유 플랫폼 - 분쟁 해결 시스템 file 졸리운_곰 2023.12.27 6
1181 [ 一日30分 인생승리의 학습법] 블록체인과 IPFS를 이용한 안전한 데이터 공유 플랫폼 - 개념과 리뷰 시스템 file 졸리운_곰 2023.12.27 4
1180 [ 一日30分 인생승리의 학습법] 소켓 CLOSE_WAIT 발생 현상 및 처리 방안 file 졸리운_곰 2023.12.03 7
1179 [ 一日30分 인생승리의 학습법] robots 설정하기 졸리운_곰 2023.12.03 3
1178 [ 一日30分 인생승리의 학습법] A Tutorial and Elementary Trajectory Model for the Differential Steering System of Robot Wheel Actuators : 로봇 휠 액츄에이터의 차동 조향 시스템에 대한 튜토리얼 및 기본 궤적 모델 file 졸리운_곰 2023.11.29 6
1177 [ 一日30分 인생승리의 학습법] Streamline Your MLOps Journey with CodeProject.AI Server : CodeProject.AI 서버로 MLOps 여정을 간소화하세요 file 졸리운_곰 2023.11.25 2
1176 [ 一日30分 인생승리의 학습법] Comparing Self-Hosted AI Servers: A Guide for Developers / : 자체 호스팅 AI 서버 비교: 개발자를 위한 가이드 file 졸리운_곰 2023.11.25 10
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED