{"id":18966413,"url":"https://github.com/fengliufeseliud/pyhp-web","last_synced_at":"2025-04-19T14:21:55.226Z","repository":{"id":59137512,"uuid":"531095455","full_name":"FengLiuFeseliud/PyHP-web","owner":"FengLiuFeseliud","description":"Python Hypertext Preprocessor Web 服务端，在请求页面时后端执行 Html 文件中的 Python 代码生成动态网页 （类似 PHP）","archived":false,"fork":false,"pushed_at":"2022-09-12T09:06:30.000Z","size":75,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-11T19:21:31.308Z","etag":null,"topics":["asyncio","hypertext-preprocessor","language","php","pyhp","python3","server","web"],"latest_commit_sha":null,"homepage":"","language":"Python","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/FengLiuFeseliud.png","metadata":{"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}},"created_at":"2022-08-31T13:23:50.000Z","updated_at":"2023-08-08T07:22:07.000Z","dependencies_parsed_at":"2022-09-13T02:11:02.143Z","dependency_job_id":null,"html_url":"https://github.com/FengLiuFeseliud/PyHP-web","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FengLiuFeseliud%2FPyHP-web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FengLiuFeseliud%2FPyHP-web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FengLiuFeseliud%2FPyHP-web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FengLiuFeseliud%2FPyHP-web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FengLiuFeseliud","download_url":"https://codeload.github.com/FengLiuFeseliud/PyHP-web/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249213735,"owners_count":21231096,"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":["asyncio","hypertext-preprocessor","language","php","pyhp","python3","server","web"],"created_at":"2024-11-08T14:37:00.909Z","updated_at":"2025-04-16T07:33:09.837Z","avatar_url":"https://github.com/FengLiuFeseliud.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PyHP-web\r\n\r\n一种 Python 轻量异步 Web 服务端 (原生异步 socket 实现)，在请求页面时后端执行 Html 文件中的 Python 代码动态生成页面\r\n\r\n可以在 Html 文件中使用各种 Python 库，非常适合不用处理大量请求的 web 线上工具\r\n\r\n![img](https://img.sakuratools.top/docs/pyhp/pyhp0.png@0x0x0.5x80)\r\n\r\n## 安装\r\n\r\npyhp 安装使用 pip\r\n\r\n```bash\r\npip install pyhpweb\r\n```\r\n\r\n## Demo\r\n\r\n后端代码\r\n\r\n```python\r\n\u003c?py \r\n    import time \r\n\r\n    time = time.asctime(time.localtime(time.time()))\r\n?\u003e\r\n\u003cdiv\u003e\r\n    \u003c?py print(f\"\u003ch2\u003e{time}\u003c/h2\u003e\") ?\u003e\r\n    \u003cdiv\u003e\r\n        \u003ch3\u003e GET \u003c/h3\u003e\r\n        \u003cform action=\"\" method=\"GET\"\u003e\r\n        First name: \u003cinput type=\"text\" name=\"firstName\"\u003e\u003cbr\u003e\r\n        Last name: \u003cinput type=\"text\" name=\"lastName\"\u003e\u003cbr\u003e\r\n        \u003cinput type=\"submit\" value=\"提交\"\u003e\r\n        \u003c/form\u003e\r\n    \u003c/div\u003e\r\n    \u003cdiv\u003e\r\n        \u003ch3\u003e POST \u003c/h3\u003e\r\n        \u003cform action=\"\" method=\"POST\"\u003e\r\n        First name: \u003cinput type=\"text\" name=\"firstName\"\u003e\u003cbr\u003e\r\n        Last name: \u003cinput type=\"text\" name=\"lastName\"\u003e\u003cbr\u003e\r\n        \u003cinput type=\"submit\" value=\"提交\"\u003e\r\n        \u003c/form\u003e\r\n    \u003c/div\u003e\r\n\u003c/div\u003e\r\n\r\n\u003c?py\r\n    from pyhpweb import __version__\r\n\r\n    print(\r\n        \"\u003cp\u003ehttp_version: %s\u003c/p\u003e\" % request_path[\"http_version\"],\r\n        \"\u003cp\u003erequest_mode: %s\u003c/p\u003e\" % request_path[\"mode\"],\r\n        \"\u003cp\u003erequest_path: %s\u003c/p\u003e\" % request_path[\"path\"],\r\n        \"\u003cp\u003eurl: %s\u003c/p\u003e\" % url,\r\n        f\"\u003cp\u003eget: {get}\u003c/p\u003e\",\r\n        f\"\u003cp\u003epost: {post}\u003c/p\u003e\",\r\n        f\"\u003cp\u003ecookie: {cookie}\u003c/p\u003e\",\r\n        f\"\u003cp\u003erequest_header: {request_header}\u003c/p\u003e\",\r\n        f\"\u003cp\u003erequest_data: {request_data}\u003c/p\u003e\",\r\n        f\"\u003cp\u003ePyHP version {__version__}\u003c/p\u003e\"\r\n    ) \r\n?\u003e\r\n\r\n```\r\n\r\n客户端请求生成动态页面\r\n\r\n![img](https://img.sakuratools.top/docs/pyhp/pyhp1.png@0x0x0.8x80)\r\n\r\n![img](https://img.sakuratools.top/docs/pyhp/pyhp2.png@0x0x0.8x80)\r\n\r\n## 快速入门\r\n\r\n使用 PyHP 时需要先启动 PyHP 服务，如下创建一个最简单的服务器文件，运行后启动 PyHP 服务，默认网站根目录为服务器文件所在文件夹，如果 Linux 下有安装 uvloop PyHP 将自动启用\r\n\r\n```python\r\nfrom pyhpweb import PyHP_Server\r\n\r\nPyHP_Server().start()\r\n```\r\n\r\n默认启动后可以访问 [http://127.0.0.1:5000/](http://127.0.0.1:5000/)\r\n\r\n### 主页\r\n\r\n使用 `.html` `.py` `.pyhtml` `.pyh` 的文件都会被 pyhp 解析，不过还是推荐使用 `.pyhtml` `.pyh`，PyHP 服务默认启动后主页为网站路径下的 `index.pyh` ，在没有主页时访问 [http://127.0.0.1:5000/](http://127.0.0.1:5000/) 会发生 404\r\n\r\n简单创建一个主页显示 PyHP 服务已经启动\r\n\r\n```python\r\n\u003c?py\r\n    from pyhpweb import __version__\r\n    \r\n    # 这里的 print 将向页面输入\r\n    print(f\"\u003ch2\u003ePyHP v{__version__}\u003c/h2\u003e\")\r\n?\u003e\r\n\r\n\u003ch3\u003eRun in Server\u003c/h3\u003e\r\n```\r\n\r\n效果\r\n\r\n![img](https://img.sakuratools.top/docs/pyhp/pyhp3.png@0x0x0.8x80)\r\n\r\n### 代码块\r\n\r\nPyHP 在 html 页面中的任何地方都可以执行 Python 代码只需要使用 `\u003c?py 你的代码 ?\u003e` 说明\r\n\r\n前面代码块中定义的变量，在后面的代码块都可以使用，但是前面代码块引用的模块，在后面的代码块不可以使用\r\n\r\n代码块 `print` 会向页面输出，代码块 `print` 的数据将在这块代码块执行完后，替换这块代码块 （代码块在哪个元素中 `print` 的数据就会在哪个元素中，如果需要直接输出请求数据使用 `html_encode` 可以防止 xss 攻击 ,`from pyhp.tools import html_encode` 引用 `html_encode`\r\n\r\n```python\r\n\u003c!DOCTYPE html\u003e\r\n\u003chtml lang=\"zh-CN\"\u003e\r\n\u003cmeta charset=\"utf-8\"\u003e\r\n\u003chead\u003e\r\n    \u003cmeta charset=\"utf-8\"\u003e\r\n    \u003ctitle\u003e测试代码块\u003c/title\u003e\r\n\u003c/head\u003e\r\n\r\n\u003c!-- 标准代码块 --\u003e\r\n\u003c?py\r\n    p_style = \"color:blue;text-align:center\"\r\n    p_text = \"Hi PyHP!!!\"\r\n?\u003e\r\n\r\n\u003cbody\u003e\r\n    \u003c!-- 行代码块 --\u003e\r\n\r\n    \u003c!-- 变量输出 动态样式 动态內容 --\u003e\r\n    \u003cp style=\"\u003c?py print(p_style) ?\u003e\"\u003e\u003c?py print(p_text) ?\u003e\u003c/p\u003e\r\n\r\n    \u003c!-- 单行输出多个元素 --\u003e\r\n    \u003c?py print(f'\u003cp style=\"{p_style}\"\u003eprint ps {p_text}\u003c/p\u003e\\n'*10) ?\u003e\r\n    \r\n    \u003chr\u003e\r\n\r\n    \u003c!-- 元素中的代码块 --\u003e\r\n\r\n    \u003cdiv\u003e\r\n        \u003c!-- 向元素中输出多个元素 --\u003e\r\n        \u003c?py\r\n        for i in range(0, 10):\r\n            print(f'\u003cp style=\"{p_style}\"\u003efor in {i} {p_text}\u003c/p\u003e\\n')\r\n        ?\u003e\r\n    \u003c/div\u003e\r\n\u003c/body\u003e\r\n\r\n```\r\n\r\n## 非阻塞生成页面\r\n\r\nPyHP 如果一个页面生成在执行 io 操作不会影响其他页面\r\n\r\n```python\r\n\u003c?py \r\n    \"\"\"\r\n    pyhp 在执行页面生成时不会阻塞其他页面\r\n\r\n    注意 页面不要写永远阻塞的代码\r\n    请求永远阻塞代码数量一多将会导致服务器卡死 (都去执行永远阻塞的代码了)\r\n    \"\"\"\r\n    import time\r\n    # 模拟 io 操作, 这时候可以去看看别的页面是否会被影响\r\n    time.sleep(30)\r\n    print(\"ok\")\r\n?\u003e\r\n```\r\n\r\n## 超级全局变量\r\n\r\n超级全局变量为 PyHP 定义的变量，在代码块的所有作用域中都可用\r\n\r\n这里列出常用的，详细查看文档\r\n\r\n\u003e **`html`**：当前代码块所在的 Py_Html 对象\r\n\u003e\r\n\u003e **`html.header`**：页面响应头, 设置响应头html.header = {\"响应类型\": 值}\r\n\u003e\r\n\u003e **`html.response`**：页面响应行, 设置响应行 html.response = {\"响应类型\": 值}, 响应类型: code: 响应码, msg: 响应内容, http_version: http 版本\r\n\u003e\r\n\u003e **`request_header`**：请求头\r\n\u003e\r\n\u003e **`request_path`**：请求模式 / 请求路径  /  请求 HTTP 版本\r\n\u003e\r\n\u003e **`url`**：请求 URL\r\n\u003e\r\n\u003e **`post`**： POST 数据\r\n\u003e\r\n\u003e **`get`**： GET 数据\r\n\u003e\r\n\u003e **`cookie`**: Cookie 数据\r\n\r\n输出测试\r\n\r\n```python\r\n\u003c?py\r\n    from pyhpweb import __version__\r\n    from pyhpweb.tools import html_encode\r\n\r\n    print(\r\n        html_encode(str(html)),\r\n        \"\u003chr\u003e\\n\u003cp\u003e请求参数\u003c/p\u003e\",\r\n        \"\u003cp\u003erequest_path: %s\u003c/p\u003e\" % request_path,\r\n        \"\u003cp\u003eurl: %s\u003c/p\u003e\" % url,\r\n        f\"\u003cp\u003eget: {get}\u003c/p\u003e\",\r\n        f\"\u003cp\u003epost: {post}\u003c/p\u003e\",\r\n        f\"\u003cp\u003ecookie: {cookie}\u003c/p\u003e\",\r\n        \"\u003chr\u003e\\n\u003cp\u003e请求头\u003c/p\u003e\",\r\n        f\"\u003cp\u003erequest_header: {request_header}\u003c/p\u003e\",\r\n        \"\u003chr\u003e\\n\u003cp\u003e响应头\u003c/p\u003e\",\r\n        f\"\u003cp\u003eresponse: {html.response}\u003c/p\u003e\",\r\n        f\"\u003cp\u003eheader: {html.header}\u003c/p\u003e\",\r\n        \"\u003chr\u003e\",\r\n        f\"\u003cp\u003ePyHP version {__version__}\u003c/p\u003e\"\r\n    )\r\n```\r\n\r\n## include 包含文件\r\n\r\nPyHP 中的 `include` 与 PHP 类似, 可以导入页面并执行里面的 Python 代码并把页面写入当前页面\r\n\r\n被包含页面执行完后可以更新包含它的文件中的变量与设置的 Cookie, 被包含的页面也可以使用包含它的文件中的变量与响应头与响应行 , `include` `update_header` 为 `True` 时, 被包含可以允许更新包含它的文件的响应头与响应行\r\n\r\n`include` 导入页面错误时不会影响后面代码执行\r\n\r\n```python\r\n\u003c?py\r\n    print(\"\u003ch1\u003einclude cookie.pyhtml \u003c/h1\u003e\")\r\n\r\n    # 相对路径引入\r\n    include(\"cookie.pyhtml\")\r\n\r\n    print(\"\u003cbr\u003e\u003cbr\u003e\u003ch1\u003einclude vals.pyhtml \u003c/h1\u003e\")\r\n\r\n    # 相对路径引入 ./\r\n    include(\"./vals.pyhtml\")\r\n\r\n    print(\"\u003cbr\u003e\u003cbr\u003e\u003ch1\u003einclude json.pyhtml \u003c/h1\u003e\")\r\n\r\n    # 相对路径引入 ../\r\n    include(\"../demo/json.pyhtml\")\r\n    \"\"\"\r\n    将更新响应头为 Content-Type: application/json\r\n    include(\"../demo/json.pyhtml\", update_header=True)\r\n    \"\"\"\r\n\r\n    print(\"\u003cbr\u003e\u003cbr\u003e\u003ch1\u003einclude test.pyhtml \u003c/h1\u003e\")\r\n\r\n    # 绝对路径引入\r\n    include(\"/home/sakura/pyhp-web/demo/demo/test.pyhtml\")\r\n?\u003e\r\n\r\n\u003cbr\u003e\u003cbr\u003e\u003ch1\u003einclude end ...\u003c/h1\u003e\r\n```\r\n\r\n## 自定义错误页\r\n\r\n想要自定义错误页, 首先需要指定错误页名称 `web_error_page` 参数, 错误页必须在网站根目录下\r\n\r\n```python\r\nfrom pyhpweb import PyHP_Server\r\n\r\nPyHP_Server(\r\n    web_error_page=\"error.pyhtml\"\r\n).start()\r\n```\r\n\r\n然后就可以自定义错误页为 `web_error_page` 参数, 错误页会额外获得错误数据\r\n\r\n```python\r\n\u003ch1\u003e自定义错误页\u003c/h1\u003e\r\n\r\n\u003c?py \r\n    \"\"\"\r\n    错误页会额外提供 error, error_url 内置变量\r\n    并且响应行也会被修改\r\n    \"\"\"\r\n    print(\r\n        f\"\u003cp\u003eresponse: {html.response}\u003c/p\u003e\",\r\n        f\"\u003cp\u003eresponse_data: {html.get_response()}\u003c/p\u003e\",\r\n        f\"\u003cp\u003eerror_url: {error_url}\u003c/p\u003e\",\r\n        f\"\u003cp\u003eerror_class_name: {type(error[0]).__name__}\u003c/p\u003e\",\r\n        \"\u003cp\u003eerror_msg: %s\u003c/p\u003e\" % error[0],\r\n        f\"\u003cp\u003eerror: {error}\u003c/p\u003e\"\r\n    )\r\n?\u003e\r\n```\r\n\r\n## 使用 Cookie\r\n\r\n使用 set_cookie 设置 cookie, set_cookie max_age 默认 -1 立刻过期, max_age 为 None 时于客户端被关闭时失效\r\n\r\n```python\r\n\u003c?py\r\n    from pyhpweb.tools import full_date\r\n    \r\n    if not cookie:\r\n        \"\"\"\r\n        当 get 数据有 nomaxage 项时 (cookie.pyhtml?nomaxage=)\r\n        这个 Cookie 将在浏览器被关闭时失效\r\n        \"\"\"\r\n        if not \"nomaxage\" in get:\r\n            # max_age Cookie 有效时长 (秒)\r\n            # max_age -1 或者 0 Cookie 立刻过期\r\n            set_cookies({\r\n                \"text\": \"30秒后过期!!!\",\r\n                \"set-time\": full_date(),\r\n            }, max_age=30)\r\n            print(\"\u003ch1\u003e没有 Cookie 设置 Cookie\u003c/h1\u003e\")\r\n        else:\r\n            # max_age 为 None 时于客户端被关闭时失效\r\n            set_cookies({\r\n                \"text\": \"浏览器被关闭时失效!!!\",\r\n                \"set-time\": full_date(),\r\n            }, max_age=None)\r\n            print(\"\u003ch1\u003e没有 Cookie 设置 Cookie, 这个 Cookie 将在浏览器被关闭时失效\u003c/h1\u003e\")\r\n\r\n    elif \"nocookie\" in get:\r\n        \"\"\"\r\n        当 get 数据有 nocookie 项时 (cookie.pyhtml?nocookie=)\r\n        删除所有 cookie\r\n        \"\"\" \r\n        # set_cookies max_age 默认 -1 立刻过期\r\n        set_cookies(cookie)\r\n        print(\"\u003ch1\u003e删除所有 cookie \u003c/h1\u003e\")\r\n\r\n    else:\r\n        print(\"\u003ch1\u003ecookie str: %s\u003c/h1\u003e\" % request_header[\"cookie\"])\r\n        print(\"\u003ch1\u003ecookie: %s\u003c/h1\u003e\" % cookie)\r\n?\u003e\r\n```\r\n\r\n## Json Api\r\n\r\n```python\r\n\u003c?py\r\n    from pyhpweb import Content_Type, __version__\r\n    import json\r\n\r\n    # 设置请求头 Content-Type 为 json\r\n    html.header = {\r\n        \"Content-Type\": Content_Type[\"json\"],\r\n    }\r\n\r\n    data = {\r\n        \"code\": 200, \r\n        \"msg\": \"OK\",\r\n        \"data\": {   \r\n            \"request_path\": request_path,\r\n            \"request_header\": request_header,\r\n            \"url\": url,\r\n            \"get\": get,\r\n            \"post\": post,\r\n            \"version\": __version__\r\n        }\r\n    }\r\n\r\n    # json.dumps json 序列化后输出至页面\r\n    print(json.dumps(data))\r\n?\u003e\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffengliufeseliud%2Fpyhp-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffengliufeseliud%2Fpyhp-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffengliufeseliud%2Fpyhp-web/lists"}