主頁 > .NET開發 > 介紹一個基于 .NET 的船新 PHP SDK + Runtime: PeachPie

介紹一個基于 .NET 的船新 PHP SDK + Runtime: PeachPie

2020-09-14 09:23:33 .NET開發

前言

這幾天想基于 .NET Core 搞一個自己的博客網站,于是在網上搜刮各種博客引擎,找到了這些候選:Blogifier、Miniblog 以及 edi 寫的 Moonglade,

Blogifier:這是前端是個 Angular SPA 應用,不利于 SEO,同時首屏加載速度慢,因此排除,

Miniblog:顧名思義 Mini,可以完美承載內容但是主題實在是過于簡單,沒有可自定義性,因此排除,

Moonglade:總體感覺不錯,界面設計得也很好,功能全面,然而需要 SQL Server 作為資料庫,然而 SQL Server 雖然有 Linux 版本,但受限于主機配置和預算因此也被排除,

難道就沒有適合我需求的博客引擎了嗎?答案當然是:有,

眾所周知 PHP 是世界上最好的語言(滑稽),還是眾所周知有一個叫做 WordPress 的博客引擎生態非常龐大,而且是使用 PHP 構建的,

可是 PHP 和 .NET 又有什么關系呢?

PeachPie

PeachPie 是一個完全構建于 .NET Standard 之上的一套完整的 PHP SDK + Runtime,包含編譯器和運行時等等,兼容 PHP 5.4-7.4(當然部分功能仍在開發中),

官網:https://www.peachpie.io

那么 PeachPie 有什么優點呢:

  • 開源:https://github.com/peachpiecompiler/peachpie
  • 跨平臺:因為 PeachPie 完全構建于 .NET 之上,因此也就跟著跨平臺了,Windows、MacOS、Linux 等等,從架構上跨 x86、x86_64、ARM、ARM64,未來甚至還會有 MIPS、MIPS64、Risc-V 等等......
  • 純托管代碼:借助 VS 強大的除錯器和 IDE 體驗,從開發、除錯到測驗、Profile 一條龍非常爽
  • 編譯:PHP 是沒有編譯之說的,這門動態型別語言和 Python 面臨一樣的問題,幾乎無法在編譯時發現代碼中的錯誤,即便借助 linter 診斷出了語法錯誤也很難診斷出型別的錯誤,而 PeachPie 則有完善的編譯器套件將 PHP 代碼完整的編譯為 .NET Standard 程式集,意味著在編譯期就做好了語法和型別檢查,保證了運行時不會因為代碼問題導致程式崩潰,同時應用分發的時候也不需要源代碼,確保了原始碼安全
  • 與 .NET 互操作:PeachPie 在保留了 PHP 原本的生態基礎上做到了 PHP 和 .NET 的互操作,一個 PeachPie 專案不但可以使用 PHP 原有生態中的包和插件,還能享受 .NET 的生態,快樂超級加倍
  • 運行在 .NET 上:CLR/CoreCLR 自帶久經考驗的 JIT 和 GC,因此通過 PeachPie 編譯的程式集運行在 CLR/CoreCLR 之上則無需做任何的代碼改動即可享受到這些東西,在 php-bench 中,借助 CoreCLR 平臺的 JIT,函式呼叫性能拉開了原來 PHP 幾個數量級
  • .NET Foundation 專案:背后有 .NET Foundation 支持,瓦利亞高品質,有保證

可是有人就要問了,為什么我不直接用 PHP 而是選用 PeachPie 曲線救國呢?

因為我樂意,雨女無瓜(逃

開始使用

本文開發環境采用 Visual Studio Code(需要安裝 PeachPie 插件),當然你也可以用 Visual Studio 等其他開發工具,

安裝 PeachPie 最新的專案模板:

dotnet new -i Peachpie.Templates::*

然后就會出現三個新的專案模板:Console Application、Class library 和 ASP.NET Core Empty,

我們這次整個 Console Application 看看,

dotnet new console -lang PHP

然后隨便寫點代碼:

<?php

function main()
{
    $students = 
        array(
            array("first_name" => "Joe", "score" => 83, "last_name" => "Smith"),
            array("first_name" => "Frank", "score" => 92, "last_name" => "Barbson"),
            array("first_name" => "Benji", "score" => 90, "last_name" => "Warner")   
        );
    
    foreach ($students as $value) {
        echo $value["first_name"], " ", $value["last_name"], "'s score is ", $value["score"], "\n";
    }
}

main();

用配置 .NET Core 專案的方式寫好 Visual Studio Code 需要的 tasks.json 和 launch.json,隨便下點斷點然后編譯 + F5 運行!

編譯輸出(請無視掉我的霓虹語電腦環境):

.NET Core 向け Microsoft (R) Build Engine バージョン 16.7.0-preview-20220-01+80e487bff
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です,
  プレビュー版の .NET Core を使用しています,https://aka.ms/dotnet-core-preview をご覧ください
  PeachPie PHP Compiler version 0.9.981+565af85b9aafc42fe1af2f30ccd73ff093a2fad7
  PeachPieConsole -> C:\Users\hez20\source\repos\PeachPieConsole\bin\Debug\netcoreapp3.1\PeachPieConsole.dll

ビルドに成功しました,
    0 個の警告
    0 エラー

経過時間 00:00:12.98

Voila!

Debug

輸出:

Joe Smith's score is 83
Frank Barbson's score is 92
Benji Warner's score is 90

如果去掉打錯一個變數 $value 變成 $vuale 會怎么樣呢?

<?php

function main()
{
    $students = 
        array(
            array("first_name" => "Joe", "score" => 83, "last_name" => "Smith"),
            array("first_name" => "Frank", "score" => 92, "last_name" => "Barbson"),
            array("first_name" => "Benji", "score" => 90, "last_name" => "Warner")   
        );
    
    foreach ($students as $value) {
        echo $vuale["first_name"], " ", $value["last_name"], "'s score is ", $value["score"], "\n";
    }
}

main();

編譯輸出:

.NET Core 向け Microsoft (R) Build Engine バージョン 16.7.0-preview-20220-01+80e487bff
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です,
  プレビュー版の .NET Core を使用しています,https://aka.ms/dotnet-core-preview をご覧ください
  PeachPie PHP Compiler version 0.9.981+565af85b9aafc42fe1af2f30ccd73ff093a2fad7
program.php(13,14): warning PHP5007: Undefined variable: $vuale [C:\Users\hez20\source\repos\PeachPieConsole\PeachPieConsole.msbuildproj] 
  PeachPieConsole -> C:\Users\hez20\source\repos\PeachPieConsole\bin\Debug\netcoreapp3.1\PeachPieConsole.dll

ビルドに成功しました,

program.php(13,14): warning PHP5007: Undefined variable: $vuale [C:\Users\hez20\source\repos\PeachPieConsole\PeachPieConsole.msbuildproj] 
    1 個の警告
    0 エラー

経過時間 00:00:09.51

由于上述代碼在 PHP 中是合法代碼,因此為了保持兼容性,PeachPie 不會報錯而是給了警告,

但如果我們少一個分號呢:

<?php

function main()
{
    $students = 
        array(
            array("first_name" => "Joe", "score" => 83, "last_name" => "Smith"),
            array("first_name" => "Frank", "score" => 92, "last_name" => "Barbson"),
            array("first_name" => "Benji", "score" => 90, "last_name" => "Warner")   
        )
    
    foreach ($students as $value) {
        echo $value["first_name"], " ", $value["last_name"], "'s score is ", $value["score"], "\n";
    }
}

main();

編譯輸出:

.NET Core 向け Microsoft (R) Build Engine バージョン 16.7.0-preview-20220-01+80e487bff
Copyright (C) Microsoft Corporation.All rights reserved.

  復元対象のプロジェクトを決定しています...
  復元対象のすべてのプロジェクトは最新です,
  プレビュー版の .NET Core を使用しています,https://aka.ms/dotnet-core-preview をご覧ください
  PeachPie PHP Compiler version 0.9.981+565af85b9aafc42fe1af2f30ccd73ff093a2fad7
program.php(12,5): error PHP2014: Syntax error: unexpected token 'foreach' [C:\Users\hez20\source\repos\PeachPieConsole\PeachPieConsole.msbuildproj]

ビルドに失敗しました,

program.php(12,5): error PHP2014: Syntax error: unexpected token 'foreach' [C:\Users\hez20\source\repos\PeachPieConsole\PeachPieConsole.msbuildproj]
    0 個の警告
    1 エラー

経過時間 00:00:01.77

這次就會直接報錯了,

由此可見,使用 PeachPie 能夠無需第三方工具輔助,直接在編譯時就驗證代碼正確性,對專案的健壯性有很大幫助,

PHP 與 .NET 互操作

我們試試互操作,在 PHP 里面創建一個 .NET 中的 HashSet<TValue>

<?php

function main()
{
    $list = new System\Collections\Generic\HashSet<string>;
    $list->Add("test");
    $list->Add("hello");
    $list->Add("hello");
    $list->Add("lol");
    foreach ($list as $key => $value) {
        echo $key, ": ", $value, "\n";
    }
}

main();

輸出:

0: test
1: hello
2: lol

完美,另外,鑒于 PHP 代碼最后都會被編譯成 .NET Standard 程式集,因此反過來當然也沒問題,就不做介紹了,

一些坑

PeachPie 已經發展了好幾年的時間了,盡管大多數 PHP 代碼都能正常運行,但是標準庫仍存在一些兼容性問題,具體可以去這里跟蹤:https://docs.peachpie.io/compatibility-status ,

由于目前還在補全兼容性問題,所以很多優化作業(比如陣列的優化)都沒有做,性能方面還有很大的提升空間,

不過官方目前開發進度十分快,因此短時間內就能看到大量的新庫函式被實作,到目前已經是 0.9.800,1.0 正式版也快要發布了,很快就能正式投入生產使用啦,

Blog 搭建

回到前面的主題,有了 PeachPie,我就能把 WordPress 放到 .NET Core 上面跑啦,

當然,直接下載下來 WordPress 的源代碼編譯跑到 ASP.NET Core 上面時會出現一些問題,比如資源加載全部 404,這是因為 PeachPie 在編譯 PHP 代碼時默認不會將非 .php 的檔案包含到編譯程序中,我們需要修改 .msbuildproj 調整專案屬性將資源檔案包含在編譯程序中,并作為 Content 引入,

另外由于 WordPress 首次配置會現場生成一個 config.php 檔案,但是由于該檔案是編譯后的程式集在運行時生成的,未參與編譯程序,因此運行時是找不到這個類的,除非重新編譯一遍,因此我們想采用更清真的方式,直接在 appsettings.json 里面寫入配置然后運行時讀入代替原來的 config.php,

總之需要經過一系列操作,并且撰寫少量代碼,不過,PeachPie 已經幫我們做好了這一切:iolevel 提供了一個即插即用的 WordPress 包 PeachPied.WordPress.AspNetCore(https://github.com/iolevel/wpdotnet-sdk ),可直接作為 ASP.NET Core 中間件使用,非常方便,

那么事情就簡單了:

dotnet new web
dotnet add package PeachPied.WordPress.AspNetCore --version 1.0.0-beta980

然后撰寫少量服務端代碼,配置一下 https 跳轉、回應壓縮和靜態檔案什么的,再加入 WordPress 中間件:

Startup.cs

using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace KeBlogs
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddResponseCompression(options =>
            {
                options.Providers.Add<BrotliCompressionProvider>();
                options.Providers.Add<GzipCompressionProvider>();
                options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] {
                    "image/svg+xml",
                    "image/png",
                    "font/woff",
                    "font/woff2",
                    "font/ttf",
                    "font/eof",
                    "image/x-icon",
                    "application/json",
                    "application/octet-stream" });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseHttpsRedirection();
            app.UseResponseCompression();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();

            app.UseWordPress();
        }
    }
}

代碼部分搞定,當然上述代碼你也可以用 PHP 來寫,

然后在 appsettings.json 寫入自己的配置,比如(SALT 部分可以沒有):

{
  "WordPress": {
    "dbhost":        "localhost",
    "dbpassword":    "password",
    "dbuser":        "root",
    "dbname":        "wordpress",
    "dbTablePrefix": "wp_",
    "SALT": {
      "AUTH_KEY":         "r(EoMbKEvlg){+!T42fh-e+~IGj-4q}g8HHB9hjbiC0J*ySU1Y*3z[3c}F;6=TA5",
      "AUTH_SALT":        "q0#AzvJ*[4~Bexa9*M(sC_#pDuGQBdjL1}j*RilSe0ku]P~KuTir[7PxjE:4)_zR",
      "LOGGED_IN_KEY":    "!AAienFSridCUzF(v}m#}_;+t%Rclg;mOPKwe;w7dN0M{d,]?8V+TRW_UG)tSswa",
      "LOGGED_IN_SALT":   "C=(4(8WPMeRu_h?g7!ddI*P:+SYU=3C%g)92oV}-y5tE0r?DHWl!fjPOp=bjx2YJ",
      "NONCE_KEY":        "Z[e37@=y)m.CHa:OSldh#RT@nIZxKYGwu!/hd:vK#^{_Ec7e{KNb(G.8ch/MkH(d",
      "NONCE_SALT":       ";v7Wv/BV)Pz{W,FaAKC0buH*5U4:g]qn~;b94x]f8=lm6!yyYSbW5*2y*kRXXEF5",
      "SECURE_AUTH_KEY":  "pc}_Pv52,m=j9l#llSkLVQib.Zm!;9FRzg:{(G]tM8}[}]pPDwB4k{xV+!e)9lmR",
      "SECURE_AUTH_SALT": "#n]+o^w/%-~MVzf{AUuxUAwF[n03r{kr^r1V?wqQ?Vjt}!0HSkCB-):u-ra1%tB="
    },
    "constants": {
    }
  }
}

然后發布我們的 WordPress!

dotnet publish -c Release

最后打包 bin/Release/netcoreapp3.1/publish 上傳到服務器上面,搭建好資料庫然后運行即可,

完結撒花

進入管理面板,大多數主題、插件都能正常作業,安裝點主題,配置配置插件和 SMTP,就全部搞定啦,

Admin

記憶體占用 195 MB,運行在 .NET Core 3.1.3 上,非常清真!

至此我的 Blog 搭建完成,歡迎大家訪問:https://hez2010.com ,

評論和注冊什么的也開放了,歡迎大家常光臨~

后續我也會不斷在上面更新文章,當然,這個 Blog 上面的內容也就不僅限于編程啦,敬請期待~

Blog

從此 PHP 也是 .NET 上的一門語言了,完結撒花~

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/33266.html

標籤:.NET Core

上一篇:ASP.NET Core Windows部署使用IIS托管 服務注冊Consul時的坑

下一篇:.net core HttpClient 使用之掉坑決議(一)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more