{"id":17043376,"url":"https://github.com/guregu/php","last_synced_at":"2025-03-23T01:43:25.145Z","repository":{"id":56815225,"uuid":"524735206","full_name":"guregu/php","owner":"guregu","description":"Prolog Home Page","archived":false,"fork":false,"pushed_at":"2025-03-04T01:04:57.000Z","size":1861,"stargazers_count":71,"open_issues_count":4,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-04T02:19:28.696Z","etag":null,"topics":["cgi","prolog","www"],"latest_commit_sha":null,"homepage":"https://php.energy","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/guregu.png","metadata":{"funding":{"github":"guregu"},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-14T17:22:31.000Z","updated_at":"2025-03-04T01:05:00.000Z","dependencies_parsed_at":"2025-03-04T02:19:32.523Z","dependency_job_id":"e93d9f54-102f-4778-81ba-329175c8b14d","html_url":"https://github.com/guregu/php","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Fphp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Fphp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Fphp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guregu%2Fphp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guregu","download_url":"https://codeload.github.com/guregu/php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245044493,"owners_count":20551898,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cgi","prolog","www"],"created_at":"2024-10-14T09:29:23.789Z","updated_at":"2025-03-23T01:43:25.124Z","avatar_url":"https://github.com/guregu.png","language":"HTML","funding_links":["https://github.com/sponsors/guregu"],"categories":[],"sub_categories":[],"readme":"# php: Prolog Home Page\n\nThis is an experiment using the WebAssembly version of [Trealla Prolog](https://github.com/trealla-prolog/trealla) and [Spin](https://spin.fermyon.dev/) to host websites.\nIt is a retrofuturistic combination of Prolog/C and Rust/WebAssembly.\n\n**Status**: Slowly approaching stability? Still in cowboy mode. 🤠\n\n## Demo\n\nHead on over to our beautiful homepage at [php.energy](https://php.energy/). Source code examples included.\n\n## Setup\n\n0. ~~Reconsider whether you really want to do this~~.\n1. [Install Spin](https://spin.fermyon.dev/quickstart/).\n2. Clone this repo.\n3. Configure the www root in `spin.toml`\n4. Put PHP scripts or Prolog programs in `public_html`.\n\n## Run\n\n- Run server with `make` or `spin up`.\n- Or use `make watch` for hot reloading.\n\n## Deploy to \\~the cloud\\~ 🆕\n\nAs of recently, you can deploy to the beta version of Fermyon cloud for free. Neat. [More info here](https://www.fermyon.com/blog/introducing-fermyon-cloud).\n\n1. [Get set up](https://developer.fermyon.com/cloud/deploy)\n2. `spin deploy`\n\n## Container Build\n\nSee: [Spin docs on OCI images](https://developer.fermyon.com/spin/spin-oci). Or MacGyver an image with [nixpacks](https://nixpacks.com/docs/install) and `make container` (or `make ARCH=aarch64 container` for ARM).\n\n## How does it work?\n\nIt just runs the WebAssembly version of Trealla Prolog and ~~writes CGI ([RFC 3875](https://datatracker.ietf.org/doc/html/rfc3875)) output to stdout~~\n[handles the Spin HTTP wasm component](https://github.com/guregu/trealla/blob/a53e03f5aedac92f9b8c8273360aee171fe6d160/src/wasm/spin.c#L45).\n\nSee the README in the www folder for more info on the file structure.\n\n\n## What's next?\n\n~~This currently uses the CGI mode of Spin, but with a little bit of effort we could use the fancy APIs and get outgoing HTTP and Redis and whatnot.~~ (Done?)\n\nIt'd be cool to get some kind of magic persistence going.\n\n## File Layout\n\n### public_html\n\nPut PHP templates here and they will show up in your root.\n\n## Templates\n\nFiles ending in `.html` will be interpreted as PHP templates with the following special syntax.\n\n### Queries: `\u003c?- Goal. ?\u003e`\n```prolog\n\u003c?- current_prolog_flag(version, Ver), write(Ver) ?\u003e\n\u003c?php ... ?\u003e\n```\n\nYou can use the `\u003c?- Goal. ?\u003e` (alias: `\u003c?php Goal. ?\u003e`) expression to execute Prolog (of course). \n\nBy default, all output from these blocks will be escaped to avoid XSS attacks. You can also use unsafe queries, see below.\n\n#### Unsafe queries: `\u003c?unsafe Goal. ?\u003e`\n\nYou can use the `\u003c?unsafe Goal. ?\u003e` expression to execute Prolog code without escaping its output (dangerous!).\nAvoid using this if you can.\n\nFor example, this renders a table of the numbers 1-10 and their squares:\n\n```html\n\u003ch3\u003eMath\u003c/h3\u003e\n\u003ctable\u003e\n\t\u003ctr\u003e\u003cth\u003eN\u003c/th\u003e\u003cth\u003eN²\u003c/th\u003e\u003c/tr\u003e\n\t\u003c?unsafe\n\t\tbagof([N, Square], (between(1, 10, N), Square is N^2)), Flags),\n\t\tmaplist(format(\"\u003ctr\u003e\u003ctd\u003e~w\u003c/td\u003e\u003ctd\u003e~w\u003c/td\u003e\u003c/tr\u003e\"), Flags)\n\t?\u003e\n\u003c/table\u003e\n```\n\n#### if block: `\u003c?if Goal. ?\u003e ... \u003c?end ?\u003e`\n```html\n\u003c?if current_prolog_flag(dialect, X). ?\u003e\n\tYou are using: \u003c?=X ?\u003e\n\u003c?end ?\u003e\n```\n\nConditionally executes the block if Goal succeeds. Only runs once.\n\n#### findall block: `\u003c?findall Goal. ?\u003e ... \u003c?end ?\u003e`\n```html\n\u003ctable\u003e\n\u003c?findall current_prolog_flag(Key, Value). ?\u003e\n\t\u003ctr\u003e\u003ctd\u003e\u003c?=Key ?\u003e\u003c/td\u003e\u003ctd\u003e\u003c?=Value ?\u003e\u003c/td\u003e\u003c/tr\u003e\n\u003c?end ?\u003e\n\u003c/table\u003e\n```\n\nWorks like if blocks, but with findall behavior.\n\n#### findall query: `\u003c?* Goal. ?\u003e`\n```prolog\n\u003c?* member(X, [1, 2, 3]), write(X). ?\u003e\n```\n\nWorks the same as query, but findall behavior instead of once behavior.\n\n#### Echo: `\u003c?=Var Goal. ?\u003e`\n```html\n1+1 = \u003c?=X X is 1+1. ?\u003e\n\u003cinput type=\"text\" name=\"ask\" value=\"\u003c?=Param query_param(ask, Param) ?\u003e\"\u003e\n```\n\nWorks the same as query, but echoes (writes) the variable bound to Var. Escapes output.\n\n### Assertions: `\u003c? Program ?\u003e`\n```prolog\n\u003c?\n% declare rules and facts\nbest_web_framework(php).\ngood_enough(X) :- between(1, 640, X).\n\n% \"directives\" get executed upon evaluation\n:- echo(\"hello!\").\n:- succ(68, X), write(X).\n?\u003e\n\nThe web framework of the future is \u003c?=Framework best_web_framework(Framework). ?\u003e\n```\n\nAssert facts and rules as if consulting a Prolog program. Directive syntax will call the given goal.\n\n`\u003c?prolog ... ?\u003e` is an alias for this.\n\n## API\n\n### module(spin)\n\nSee: [spin.pl](https://github.com/guregu/trealla/blob/main/library/spin.pl).\n\n```prolog\n:- module(spin, [\n\t% Inbound HTTP\n\t% Request routing\n\thttp_handler/4,\n\t% Request info\n\tcurrent_http_uri/1, current_http_method/1, current_http_body/1,\n\tcurrent_http_param/2, current_http_header/2,\n\t% Response output\n\thttp_header_set/2,\n\thttp_body_output/1,\n\thtml_content/0, html_content/1,\n\ttext_content/0, text_content/1,\n\tprolog_content/0, prolog_content/1,\n\t% Outbound HTTP\n\thttp_fetch/3,\n\t% Key-value store\n\tstore_open/1, store_open/2,\n\tstore_close/1,\n\tstore_get/3, store_exists/2,\n\tstore_keys/2,\n\tstore_set/3, store_delete/2,\n\t% PostgreSQL\n\tpostgres_open/3,\n\tpostgres_open_url/2,\n\tpostgres_execute/4,\n\tpostgres_query/5,\n\t% SQLite\n\tsqlite_open/2,\n\tsqlite_query/5,\n\tsqlite_close/1,\n\t...\n]).\n```\n\n### module(php)\n\n#### php//1\n\nPHP grammar.\n\n#### phpinfo/0\n```prolog\nphpinfo.\n```\n\nWrites HTML output, dumping the current environment and flags.\n\n#### render/1\n```prolog\nrender(+Filename).\n```\n\nRenders the given PHP file.\n\n#### html_escape/2\n```prolog\nhtml_escape(-Raw:string, +Sanitized:string).\n```\n\nEscapes string using `htmlspecialentities//1`.\n\n## FAQ\n\n### Why?\n\nWhy not?\n\n### Is this real?\n\n![phpinfo/0 output](https://user-images.githubusercontent.com/131059/184548289-46cca2e2-8bfe-4684-b96a-8f4311f03a4a.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguregu%2Fphp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguregu%2Fphp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguregu%2Fphp/lists"}