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

前言

這幾天想基於 .NET Core 搞一個本身的博客網站,因而在網上搜刮各類博客引擎,找到了這些候選:Blogifier、Miniblog 以及 edi 寫的 Moonglade。php

Blogifier:這是前端是個 Angular SPA 應用,不利於 SEO,同時首屏加載速度慢,所以排除。前端

Miniblog:顧名思義 Mini,能夠完美承載內容可是主題實在是過於簡單,沒有可自定義性,所以排除。git

Moonglade:整體感受不錯,界面設計得也很好,功能全面,然而須要 SQL Server 做爲數據庫,然而 SQL Server 雖然有 Linux 版本,但受限於主機配置和預算所以也被排除。github

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

衆所周知 PHP 是世界上最好的語言(滑稽),仍是衆所周知有一個叫作 WordPress 的博客引擎生態很是龐大,並且是使用 PHP 構建的。數據庫

但是 PHP 和 .NET 又有什麼關係呢?編程

PeachPie

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

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

那麼 PeachPie 有什麼優勢呢:安全

  • 開源:https://github.com/peachpiecompiler/peachpie
  • 跨平臺:由於 PeachPie 徹底構建於 .NET 之上,所以也就跟着跨平臺了,Windows、MacOS、Linux 等等,從架構上跨 x8六、x86_6四、ARM、ARM64,將來甚至還會有 MIPS、MIPS6四、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.AspNetCorehttps://github.com/iolevel/wpdotnet-sdk ),可直接做爲 ASP.NET Core 中間件使用,很是方便。

那麼事情就簡單了:

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

而後編寫少許服務端代碼,配置一下 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 上的一門語言了,完結撒花~

相關文章
相關標籤/搜索