*2023.04.10: mod_harbour.v2 (x64) + mysql

xBase/clipper
回覆文章
admin
Site Admin
文章: 53
註冊時間: 2014-09-23, 10:58

*2023.04.10: mod_harbour.v2 (x64) + mysql

文章 admin »

使用軟體:

代碼: 選擇全部

XAMPP release 7.4.33
  Apache 2.4.54
  PHP 7.4.33 , 8.0.25 , 8.1.12
  MariaDB 5.4.27
  OpenSSL 1.1.1p (Windows) and OpenSSL 1.1.1s (Linux and OS X)
  
Harbour
  core 2023-03-09 15:50
  hbcurl、hbssl、hbmysql
  mod_harbour.v2.1

3rd
  curl-7.87.0
  openssl-1.1.1t
  openssl-1.0.2u

Compiler
  Visual Studio 2019 (MSVC16)
1. 首先,先更新 harbour 為最新版,分別編譯出 msvc、msvc64 兩種版本.
https://github.com/harbour/core
  1. 編譯 hbssl:
    準備軟體:
    1. openssl 1.0.2u (不能用 1.0.2u 以上版本,會有錯誤!!)、
      我個人是自己編譯,自己看著辦吧!
    2. curl 7.87.0
      我是自己編譯,自己看著辦吧!
  2. 編譯 hbcurl:
    準備:
    1. openssl 1.1.1t
      下載網址:https://kb.firedaemon.com/support/solutions/articles/4000121705
    2. curl 7.87.0
編譯好之後,各自從裡面的 .\lib\ 裡面複製出 .dll 備用,到時候要複製到 apache 的 .\bin\ 目錄去,
有重複的請勿覆蓋!!

處理 XAMPP 部分:
目前 XAMPP 只有 x64 版本,且在測試 x64 過程中屢次發生錯誤,於是更新了 apache 2.4.55
下載網址:https://www.apachehaus.com/cgi-bin/download.plx
Apache 2.4.55 x64 OpenSSL 1.1.1 VS16

至於怎麼替換,上網找一下就有一堆關於 XAMPP 升級 apache 方法!!

另外,XAMPP 預設使用 mariaDB,呼叫上怪怪的,我也順便替換為 mysql 5.7.40-winx64 版本.
至於怎麼替換,也請上網找一下資料!!

當各項工具都準備好之後,就是複製了!!

將 hbssl、hbcurl、mysql 使用到的 dll 複製到 xampp\apache\bin\ 裡面去,

x86: (這部分留給 mod_harbour 使用,不是 mod_harbour.v2.1)
  1. libcrypto-1_1.dll
  2. libcurl.dll
  3. libeay32.dll
  4. libssl-1_1.dll
  5. ssleay32.dll
  6. libmysql.dll
x64:
  1. libcrypto-1_1-x64.dll
  2. libcurl.dll
  3. libeay32.dll
  4. libssh2.dll
  5. libssl-1_1-x64.dll
  6. ssleay32.dll
  7. libmysql.dll
切記!!複製進去若出現是否覆蓋訊息,請勿覆蓋,怎麼會造成 httpd 呼叫時版本錯誤問題發生!!

現在開始測試 mod_harbour.v2.1
測試過程真的是一波三折,一直出現版本問題,搞到後來才將 XAMPP 的 Apache、MariaDB 替換掉,
替換好之後程式跑起來都沒問題,結著測試 mysql,我用原來自己使用的 mysql.c、tmysql.prg 多年習慣了,
卻發生跑不起來情形,只好參照 hbmysql 將自己的程式碼全部更新過,最後才大功告成!! :lol:

測試一:參考 mod_harbour 的 clock.prg,程式碼修改如下:

代碼: 選擇全部

      <!DOCTYPE html>
      <html>
      <body>

      <canvas id="canvas" width="400" height="400"
      style="background-color:#333">
      </canvas>

      <script>
      var canvas = document.getElementById("canvas");
      var ctx = canvas.getContext("2d");
      var radius = canvas.height / 2;
      ctx.translate(radius, radius);
      radius = radius * 0.90
      setInterval(drawClock, 1000);

      function drawClock() {
        drawFace(ctx, radius);
        drawNumbers(ctx, radius);
        drawTime(ctx, radius);
      }

      function drawFace(ctx, radius) {
        var grad;
        ctx.beginPath();
        ctx.arc(0, 0, radius, 0, 2*Math.PI);
        ctx.fillStyle = 'white';
        ctx.fill();
        grad = ctx.createRadialGradient(0,0,radius*0.95, 0,0,radius*1.05);
        grad.addColorStop(0, '#333');
        grad.addColorStop(0.5, 'white');
        grad.addColorStop(1, '#333');
        ctx.strokeStyle = grad;
        ctx.lineWidth = radius*0.1;
        ctx.stroke();
        ctx.beginPath();
        ctx.arc(0, 0, radius*0.1, 0, 2*Math.PI);
        ctx.fillStyle = '#333';
        ctx.fill();
      }

      function drawNumbers(ctx, radius) {
        var ang;
        var num;
        ctx.font = radius*0.15 + "px arial";
        ctx.textBaseline="middle";
        ctx.textAlign="center";
        for(num = 1; num < 13; num++){
          ang = num * Math.PI / 6;
          ctx.rotate(ang);
          ctx.translate(0, -radius*0.85);
          ctx.rotate(-ang);
          ctx.fillText(num.toString(), 0, 0);
          ctx.rotate(ang);
          ctx.translate(0, radius*0.85);
          ctx.rotate(-ang);
        }
      }

      function drawTime(ctx, radius){
          var now = new Date();
          var hour = now.getHours();
          var minute = now.getMinutes();
          var second = now.getSeconds();
          //hour
          hour=hour%12;
          hour=(hour*Math.PI/6)+
          (minute*Math.PI/(6*60))+
          (second*Math.PI/(360*60));
          drawHand(ctx, hour, radius*0.5, radius*0.07);
          //minute
          minute=(minute*Math.PI/30)+(second*Math.PI/(30*60));
          drawHand(ctx, minute, radius*0.8, radius*0.07);
          // second
          second=(second*Math.PI/30);
          drawHand(ctx, second, radius*0.9, radius*0.02);
      }

      function drawHand(ctx, pos, length, width) {
          ctx.beginPath();
          ctx.lineWidth = width;
          ctx.lineCap = "round";
          ctx.moveTo(0,0);
          ctx.rotate(pos);
          ctx.lineTo(0, -length);
          ctx.stroke();
          ctx.rotate(-pos);
      }
      </script>

      </body>
      </html>
<?prg
  ? "debug"
// 加不加這個沒影響
//  zzz()
//  func zzz()
       if Empty( AP_Body() )
          ? "Use the postman utility to send different body values"
       else   
          AP_RPuts( AP_Body() )
       endif
       ? "method:"+AP_Method()
       cFile := AP_FileName()
       ? 'Filename full path: '+cFile
       ? 'FilePath: '+cFilePath(cFile)
       ? 'FileName: '+cFileName(cFile)
       ? 'FileExt: '+cFileExt(cFile)
       // ? 'Path Url:'+PathUrl()
       ? 'args: '+valToChar(AP_Args()) // hash
       
       //IF AP_Method() == 'GET'
          ? 'GET: '+valToChar( AP_GetPairs()) // hash
       //ELSE
          ? 'POST: '+valToChar( AP_PostPairs()) // hash
       //ENDIF
       ? 'user IP:'+AP_USERIP()
       n := AP_HEADERSINCOUNT() // 數量
       ? '---------------------'
       ? 'head: '+hb_ntos(n)
       ? '---------------------'
       For nI := 0 To n-1
           ? hb_ntos(nI)+':head['+AP_HEADERSINKEY(nI)+']:'+AP_HEADERSINVAL(nI)
       Next nI
       ? '---------------------'
       ? 'head in  (hash):'+valToChar(AP_HEADERSIN())
       ? 'head out (hash):'+valToChar(AP_HEADERSOUT()) // 送出表頭
       // AP_SetContentType( "text/html" )
       ? "abc"
       ? 'env:'+AP_GETENV('PATH')
//  return
?>

執行結果:
圖檔

測試 clock.prg 與 clock.hrb,執行結果都一樣!!

接下來測試 mysql,這個才是重點!!

代碼: 選擇全部

<?prg
//----------------------------------------------------------------//
AP_SetContentType( "text/html; charset=utf-8" )
zzz()
function zzz()
   LOCAL oServer, oRow, aStru
   LOCAL oQry
   LOCAL nI
   LOCAL aDBs := Array(0)

   ? "debug-begin..."

   Set( _SET_DATEFORMAT, "yyyy-mm-dd" )

   Do While .T.
      oServer := TMySQLServer():New( "localhost", "xyz", "12345678" )
      IF oServer:NetErr()
         ? "mySQL connect fail!!"
         Exit
      ELSE
         ? "mySQL connect success!!"
      ENDIF
      ? "socket:"+hb_ntos( oServer:nSocket )
     
      aDBs := oServer:ListDBs()
      For nI := 1 To Len(aDBs)
          ? hb_ntos(nI)+':'+aDBs[nI]+'<br>'
      Next nI
      
      oServer:SelectDB( "ss_ykqk" )
      IF oServer:NetErr()
         ? "mySQL select db fail!!"
         Exit
      ELSE
         ? "mySQL select db success!!"
      ENDIF
      
      IF oServer:SetChar('utf8') != 0
         ? "錯誤!資料庫設定編碼錯誤:[set names utf8]無法使用!"
         Exit
      ELSE
         ? "設定編碼字元為 utf8 成功!!"
      ENDIF
      
      oQry := oServer:Query( "SELECT * from prd" )
      ? "SELECT OK"
      
      IF oQry:RecCount() > 0
         ? "found data..."
         For nI := 1 To oQry:RecCount()
             ? 'PRDID:'+hb_ntos(oQry:FieldGet('PRDID'))+'/'+;
               'PD_NAM:'+oQry:FieldGet('PD_NAM')+'/'+;
               'utf8 Len:'+hb_ntos( hb_utf8Len( Trim( oQry:FieldGet('PD_NAM')) ))+'/'+;
               'big5 Len:'+hb_ntos( Len( Trim( oQry:FieldGet('PD_NAM')) ))
             oQry:Skip()
         Next nI
      ELSE
         ? "not found data!!"
      ENDIF
      oQry:End()
      Exit
   EndDo
   
   If ValType( oServer ) == 'O'
      oServer:Destroy()
   EndIf
   
return
?>
執行結果:
圖檔

測試 test_mysql.prg 與 test_mysql.hrb,執行結果都一樣!!

優點:將程式編譯成 .hrb 給客戶,能跑不能改!! :lol:
效能:跟 PHP 不相上下!! :twisted:

編譯好的 libmhapache.dll/mod_harbour.v2.so:
下載
這個 libmharbour.dll 已經包含了 tmysql 功能,執行效率好到嚇人!!

libmhapache.dll 請放入 xampp\apache\bin\
mod_harbour.v2.so 請放入 xampp\apache\modules
修改:xampp\apache\conf\extra\httpd-xampp.conf 檔案
加入:

代碼: 選擇全部

LoadFile "E:/WebServer/xampp/apache/bin/libmysql.dll"  (請自行修改路徑符合自己的環境!!)
LoadModule mod_harbourV2_module modules/mod_harbour.v2.so
MH_LIBRARY E:\WebServer\xampp\htdocs\libmhapache.dll  (請自行修改路徑符合自己的環境!!)
MH_NVMS 10
上述設定是原有 mod_harbour.v2 的設定!

我另外加了兩個設定:

代碼: 選擇全部

SetEnv RUN_AS_PHP "1"
SetEnv HB_PATH "e:\hb32mod"
RUN_AS_PHP:
  • "1" 代表要啟動我修改的 <?prg ... ?> 執行方式.
  • "0" 代表運行方式跟原作者一樣執行方式.
HB_PATH 是 harbour 目錄,運行時需要編譯 .prg,需指定 harbour 所在目錄曾能正確處理 harbour\include\
line ID: ssbbstw
WeChat ID: ssbbstw
回覆文章