{"id":34984110,"url":"https://github.com/xvxx/phd","last_synced_at":"2025-12-27T01:23:14.572Z","repository":{"id":57654808,"uuid":"229115234","full_name":"xvxx/phd","owner":"xvxx","description":"🐀 an esoteric gopher server","archived":false,"fork":false,"pushed_at":"2022-12-04T22:56:18.000Z","size":146,"stargazers_count":43,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-10-24T22:10:18.532Z","etag":null,"topics":["daemon","gopher","gopher-server","server"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/xvxx.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-19T18:27:20.000Z","updated_at":"2025-10-11T23:54:00.000Z","dependencies_parsed_at":"2023-01-24T08:00:11.682Z","dependency_job_id":null,"html_url":"https://github.com/xvxx/phd","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/xvxx/phd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fphd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fphd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fphd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fphd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xvxx","download_url":"https://codeload.github.com/xvxx/phd/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xvxx%2Fphd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28067532,"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","status":"online","status_checked_at":"2025-12-26T02:00:06.189Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["daemon","gopher","gopher-server","server"],"created_at":"2025-12-27T01:23:13.889Z","updated_at":"2025-12-27T01:23:14.566Z","avatar_url":"https://github.com/xvxx.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\n      /       |\n ___ (___  ___|\n|   )|   )|   )\n|__/ |  / |__/\n|\n--\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"./img/logo.png\"\u003e \u003cbr\u003e\n\n\u003ca href=\"https://github.com/xvxx/phd/releases\"\u003e\n\u003cimg src=\"https://img.shields.io/github/v/release/xvxx/phd?include_prereleases\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://crates.io/crates/phd\"\u003e\n\u003cimg src=\"https://img.shields.io/crates/v/phd\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/xvxx/phd/actions?query=workflow%3Abuild\"\u003e\n\u003cimg src=\"https://github.com/xvxx/phd/workflows/build/badge.svg\"\u003e\n\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n`phd` is a small, easy-to-use gopher server.\n\nPoint it at a directory and it'll serve up all the text files,\nsub-directories, and binary files over Gopher. Any `.gph` files will\nbe served up as [gophermaps][map] and executable `.gph` files will be\nrun as a program with their output served to the client, like the\nglorious cgi-bin days of yore!\n\n### ~ special files ~\n\n- **`header.gph`**: If it exists in a directory, its content will be\n  shown above the directory's content. Put ASCII art in it.\n- **`footer.gph`**: Same, but will be shown below a directory's content.\n- **`index.gph`**: Completely replaces a directory's content with what's\n  in this file.\n- **`??.gph`**: Visiting `gopher://yoursite/1/dog/` will try to render\n  `dog.gph` from disk. Visiting `/1/dog.gph` will render the raw\n  content of the .gph file.\n- **`.reverse`**: If this exists, the directory contents will be listed\n  in reverse alphanumeric order. Useful for phloggin', if you date\n  your posts.\n\nAny line in a `.gph` file that doesn't contain tabs (`\\t`) will get an\n`i` automatically prefixed, turning it into a Gopher information item.\n\nFor your convenience, phd supports **[geomyidae][gmi]** syntax for\ncreating links:\n\n    This is an info line.\n    [1|This is a link|/help|server|port]\n    [h|URL Link|URL:https://noogle.com]\n\n`server` and `port` will get translated into the server and port of\nthe actively running server, eg `localhost` and `7070`.\n\nAny line containing a tab character (`\\t`) will be sent as-is to the\nclient, meaning you can write and serve up raw Gophermap files too.\n\n### ~ dynamic content ~\n\nAny `.gph` file that is marked **executable** with be run as if it\nwere a standalone program and its output will be sent to the client.\nIt will be passed three arguments: the query string (if any), the\nserver's hostname, and the current port. Do with them what you will.\n\nFor example:\n\n    $ cat echo.gph\n    #!/bin/sh\n    echo \"Hi, world! You said:\" $1\n    echo \"1Visit Gopherpedia\t/\tgopherpedia.com\t70\"\n\nThen:\n\n    $ gopher-client gopher://localhost/1/echo?something\n    [INFO] Hi, world! You said: something\n    [LINK] Visit Gopherpedia\n\nOr more seriously:\n\n    $ cat figlet.gph\n    #!/bin/sh\n    figlet $1\n\nthen:\n\n    $ gopher-client gopher://localhost/1/figlet?hi gopher\n    [INFO]  _     _                     _\n    [INFO] | |__ (_)   __ _  ___  _ __ | |__   ___ _ __\n    [INFO] | '_ \\| |  / _` |/ _ \\| '_ \\| '_ \\ / _ \\ '__|\n    [INFO] | | | | | | (_| | (_) | |_) | | | |  __/ |\n    [INFO] |_| |_|_|  \\__, |\\___/| .__/|_| |_|\\___|_|\n    [INFO]            |___/      |_|\n\n### ~ ruby on rails ~\n\n`sh` is fun, but for serious work you need a serious scripting\nlanguage like Ruby or PHP or Node.JS:\n\n    $ cat sizes.gph\n    #!/usr/bin/env ruby\n\n    def filesize(file)\n        (size=File.size file) \u003e (k=1024) ? \"#{size/k}K\" : \"#{size}B\"\n    end\n\n    puts \"~ file sizes ~\"\n    spaces = 20\n    Dir[__dir__ + \"/*\"].each do |entry|\n        name = File.basename entry\n        puts \"#{name}#{' ' * (spaces - name.length)}#{filesize entry}\"\n    end\n\nNow you can finally share the file sizes of a directory with the world\nof Gopher!\n\n    $ phetch -r 0.0.0.0:7070/1/sizes\n    i~ file sizes ~\t(null)\t127.0.0.1\t7070\n    iCargo.toml          731B\t(null)\t127.0.0.1\t7070\n    iLICENSE             1K\t(null)\t127.0.0.1\t7070\n    iMakefile            724B\t(null)\t127.0.0.1\t7070\n    itarget              288B\t(null)\t127.0.0.1\t7070\n    iphd                 248K\t(null)\t127.0.0.1\t7070\n    iCargo.lock          2K\t(null)\t127.0.0.1\t7070\n    iREADME.md           4K\t(null)\t127.0.0.1\t7070\n    img                 96B\t(null)\t127.0.0.1\t7070\n    isizes.gph           276B\t(null)\t127.0.0.1\t7070\n    isrc                 224B\t(null)\t127.0.0.1\t7070\n\n## ~ usage ~\n\n    Usage:\n\n        phd [options] \u003croot directory\u003e\n\n    Options:\n\n        -r, --render SELECTOR  Render and print SELECTOR to stdout only.\n        -h, --host HOST        Hostname for links. [Default: {host}]\n        -p, --port PORT        Port for links. [Default: {port}]\n        -b, --bind ADDRESS     Socket address to bind to. [Default: {bind}]\n        --no-color             Don't show colors in log messages.\n\n    Other flags:\n\n        -h, --help      Print this screen.\n        -v, --version   Print phd version.\n\n    Examples:\n\n        phd ./path/to/site  # Serve directory over port 7070.\n        phd -p 70 docs      # Serve 'docs' directory on port 70\n        phd -h gopher.com   # Serve current directory over port 7070\n                            # using hostname 'gopher.com'\n        phd -r / ./site     # Render local gopher site to stdout.\n\n## ~ installation ~\n\nOn macOS you can install with [Homebrew](https://brew.sh/):\n\n    brew install xvxx/code/phd\n\nBinaries for Linux, Mac, and Raspberry Pi are available at\ngopher://phkt.io/1/releases/phd and https://github.com/xvxx/phd/releases:\n\n- [phd-v0.1.15-linux-x86_64.tar.gz][0]\n- [phd-v0.1.15-linux-armv7.tar.gz (Raspberry Pi)][1]\n- [phd-v0.1.15-macos.zip][2]\n\nJust unzip/untar the `phd` program into your `$PATH` and get going!\n\nIf you have **[cargo][rustup]**, you can install the crate directly:\n\n    cargo install phd --locked\n\n## ~ development ~\n\n    cargo run -- ./path/to/gopher/site\n\n## ~ resources ~\n\n- gopher://bitreich.org/1/scm/geomyidae/files.gph\n- https://github.com/gophernicus/gophernicus/blob/master/README.Gophermap\n- https://gopher.zone/posts/how-to-gophermap/\n- [rfc 1436](https://tools.ietf.org/html/rfc1436)\n\n## ~ todo ~\n\n- [ ] systemd config, or something\n- [ ] TLS support\n- [ ] user input sanitization tests\n\n## ~ status ~\n\nphd is no longer under active development, but the latest version works great.\n\n[0]: https://github.com/xvxx/phd/releases/download/v0.1.15/phd-v0.1.15-linux-x86_64.tar.gz\n[1]: https://github.com/xvxx/phd/releases/download/v0.1.15/phd-v0.1.15-linux-armv7.tar.gz\n[2]: https://github.com/xvxx/phd/releases/download/v0.1.15/phd-v0.1.15-macos.zip\n[map]: https://en.wikipedia.org/wiki/Gopher_(protocol)#Source_code_of_a_menu\n[gmi]: http://r-36.net/scm/geomyidae/\n[rustup]: https://rustup.rs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvxx%2Fphd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxvxx%2Fphd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxvxx%2Fphd/lists"}