Calling Prolog from php

Pengines is probably still a reasonable choice to look into. It basically provides an HTTP server. You send it a request to create a query given some source code that you can provide as a string or URL from which to download the source. The source is loaded into an isolated environment. The sandbox (which you can disable) computes the reachable call tree from the query and verifies it only contains whitelisted predicates. It than runs the query and returns the result, typically as JSON. If the result is non-deterministic you can ask for the next, etc. or stop. Queries are isolated from each other and the server does not maintain any state after the query completes.



Since you note im a newbie to prolog and this is actually more of a second semester entire semester project than a first semester chapter exercise this will take some time to understand; here are some pointers.

  1. The SWI-Prolog documentation is not written to give examples. It notes

This document is a reference manual . That means that it documents the system, but it does not explain the basics of the Prolog language and it leaves many details of the syntax, semantics and built-in primitives undefined where SWI-Prolog follows the standards. This manual is intended for people that are familiar with Prolog.

So don’t expect to find working code examples in the documentation.

  1. While Pengines (source) is a high level construct that is close to what you need,

Note: I use dark mode which makes the next two images very hard to see. To see them I right click on them and open in a new browser tab.



you will most likely be working and living in the code from the http libraries. (ref)

:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
:- use_module(library(http/http_server_files)).
:- use_module(library(http/http_files)).
:- use_module(library(pengines)).
:- use_module(pengine_sandbox:library(pengines)).
  1. I find that seeing working examples is one of the best ways to understand the code. The best way I know to find working examples is to
    a. Look for examples in the supplied code. pengine has an example directory. (examples)
    b. Look for others who have published code on GitHub. The key to find such code is to search for a word that is unique.
    pengines - pengine_create/1 (GitHub search).
    web sockets - ws_receive/2 (GitHub search).
    For going lower into code I like to search the library http_dispatch (GitHub search)
    Understand that code in the wild my be good as an example or may be horrible as an example. It is a learned skill to know which. List of GitHub accounts with quality Prolog code.

  2. Ask questions here. While you can ask on StackOverflow, StackOverflow is not really a great place to solve a problem that may need a discussion. Also it is better to ask than not to ask. The worse that can happen is that your question will not get answered. Even my questions sometimes don’t get any reply, don’t take it personally.

  3. Expect to be very frustrated often and for a long time, a week or more. Remeber that one learns more from failure than success.

    “The master has failed more times than the beginner has even tried.” - Stephen McCranie

  4. If you use machine query interface realize that it is only a few months old (ref) and I don’t know of any other examples than the one by the creator (Eric Zinda). If you choose this odds are we will be learning more from you about MQI but you will be learning Prolog from us.

  5. Don’t get bogged down in premature optimization. Get the code working correctly first, no matter how bad the code looks and/or how in effective the data structures are, then once you have it all working correctly focus on optimizations. Intel even expands on this idea. (ref)


1 Like

I put some notes on getting simple Prolog and Erlang scripts to communicate via websocket at erlang-webapp-howto/unit7 at master · roblaing/erlang-webapp-howto · GitHub

I did an example of using Prolog as the server and as the client, and the Erlang code should be replaceable with any language with websocket support.


If you are looking for something quick and dirty @joeblog example is the quickest (copied from his link above):

Write this in

:- use_module(library(http/websocket)).
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).

:- http_handler(root(pong), http_upgrade_to_websocket(pong_handler, []), [spawn([])]).

server(Port) :-
  http_server(http_dispatch, [port(Port)]).

pong_handler(Request) :-
  ws_receive(Request, Message),
  debug(websocket, "Got ~p~n", [Message]),
  format("Received ~p~n", [Message]),
  (   Message.opcode == close
  ->  ws_send(Request, close(1000, "Bye")),
      format("Pong finished~n")
  ;   ws_send(Request, text("Pong")),
      format("Sent Pong~n"),

Now in a terminal run:

$ swipl -g 'server(8001)'

while running this in another terminal:

$ websocat ws://                                                   09:26:51  ✔ 0 

You’ll get this output:

$ swipl -g 'server(8001)'
% Started server at http://localhost:8001/
1 ?- Received websocket{data:"hello\n",format:string,opcode:text}
Sent Pong
Received websocket{data:"hi\n",format:string,opcode:text}
Sent Pong
Received websocket{data:"goodbye\n",format:string,opcode:text}
Sent Pong
Received websocket{code:1000,data:"",format:string,opcode:close}
Pong finished

From there you can easily see how to connect with the server using php and websockets.


I agree with @jan that I’d start with Penguines. The MQI interface gives you full access to the power of Prolog, which can basically do anything. You could certainly use the MQI with PHP since PHP has support for regular old sockets, how to go about it is described here. But: you’ll need to build the right security and server infrastructure around it and penguines already has that.

This might be similar to what you want – it’s a sample JavaScript client that communicates with a Prolog server, sending a query and displaying the result. It has zero security and allows any Prolog command (e.g., you can use assertz/1 to create facts).

Thank you guys for all these recommendations. I really appreciate it. This community is awesome!
I will check all of these and choose the one which best suites my needs. Thanks!

Again, thanks for the kind help you gave to publish this Prolog solver. It works fine.
But I just tried to use this example to adapt it for other solvers, and nothing worked.
For a similar Quine prover working not with variables (upper case letter A), but with lower case, I get:

there was a problem:{"proof":"","formula":"TBD"}

It is not an easy task.

By the way, I got a successful result with prover on this website:
Unfortunately, the same code failed on SWISH. :frowning:

I’m sorry, without more details cannot say anything… seems it’s not a PHP problem.

Here PHP returns to Javascript the Prolog_script’ result

   header('Content-type: application/json');
   echo json_encode(['proof'=>$Proof,'formula'=>'TBD']);

Here Javascript just exposes the outcome of the remote call (from a browser to your server)

     let result = await request("<?=$_SERVER['REQUEST_URI']?>", f)
      if (result.proof)
        proof_show.textContent = result.proof
        proof_show.innerHTML = 'there was a problem:<b>'+JSON.stringify(result)+'<b>'

You should check on the server, from inside the Prolog script, why the result.proof is empty…

I would start verifying that a trace is actually doable, since the basic security policies on servers usually forbid to write in public accessible places…

Yes, you are right. It was not a PHP problem. I had just forgotten to declare a Prolog predicate in “module” at the top of the prolog file, and it work now ! I am very sorry to waste your time. Many thanks again.

1 Like

I noticed that the vertical bar used by TPTP syntax to translate the disjunction operator (eg ~ A | A ) prevents a correct output for the same Quine prover online : with

:- module(quineweb,
	   op(700, xfy, <=>),
	   op(600, xfy, =>),
	   op(500, xfy, '|'),
	   op(400, xfy, &),
	   op(300, fy, ~)

and whith replacing v by a bar in the clauses, one gets:

there was a problem:{“proof”:"",“formula”:“TBD”}

This problem does not appear with the Prolog compiler online , but it is also probably a problem with pengines. It is a pity for the syntax adopted by the logicians and computer scientists who published a lot of logical problems for provers… :frowning:

I add a correction to what I wrote: in fact, with adding round brackets to avoid confusion, using a bar instead of v works also fine. It was therefore a minor problem. I will publish soon online my work on fCube.

Sorry, I don’t fully understand the problem… (maybe Jan Burse could help ?)

If you run

?- setof(r(Z,P,A),current_op(P,A,Z),L),maplist(writeln,L).

You can see that the default precedence is set to 1105, pretty high. Could be that lowering it to 500 changes some formula meaning ?

Yes, here his the code wich works, to use the bar as symbol of disjunction (Jan Burse as Prolog programmer disagrees with this use, I remember it, but I prefer this TPTP convention over Prolog’s). For example, for fCube prover that I am going to publish online, I have this:

:- module(fcubeweb,
	   op(1200, xfy, <=>),
	   op(1110, xfy, =>),
	   op(1100, xfy, '|'),
	   op(1000, xfy, &),
	   op(500, fy, ~)

And, with taking care of writing disjunctions in clauses with round brackets, it works perefectly well.
(I remember that, if the bar symbol for disjunction if set lower, Prolog does not agree.)

FCube is online now


You could also post it as a topic in the announce category.


Thanks !

Added to Useful Prolog References section Applications making use of Prolog

You are quite welcome!

1 Like

Hello Carlo,

I wonder why the time output e.g.

% 376 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 1862013 Lips)

is not displayed on html page via your php script. I would be nice to have a workaround to display it. A suggestion?

Best wishes ,

Hi Joseph

I think PHP could capture the output of the process it started, but need some search/test, and have little time right now.

Will let you know when I have some more information…

There is no hurry Carlo, thanks, only a minor issue.