顯示具有 PHP 標籤的文章。 顯示所有文章
顯示具有 PHP 標籤的文章。 顯示所有文章

2025-03-10

使用 homebrew 安裝 apache2 和 php 環境

使用 homebrew 安裝 apache2 和 php 環境

XAMPP 的 mac 版本現在都比較老舊,而且在 macOS 15 有無法啟動 apache 的問題。 為了教學需求,在此記錄 mac 的 php 環境的建立方式。假設 homebrew 的環境已經安裝完成。 如果要使用 ubuntu vm 可以參考上一篇 https://qops.blogspot.com/2025/03/orbstack-ubuntu-224-php-56-apache2.html 的作法。

安裝 apache2

# 先查看是否已安裝 brew info apache2 # 前幾行若出現 Not installed 表示沒有安裝,後面也有設定的說明
# 安裝 brew install apache2 # 安裝後,注意預先的設定 # -- DocumentRoot is /opt/homebrew/var/www # -- 主設定檔位置 /opt/homebrew/etc/httpd/httpd.conf # -- ssl 設定檔位置 /opt/homebrew/etc/httpd/extra/httpd-ssl.conf # -- 預設的 ports 為 8080 和 8443 # 啟動服務 brew services start httpd # 在瀏覽器上查看 http://localhost:8080 # 重新啟動服務 brew services restart httpd # 停止服務 brew services stop httpd

安裝 php

這裡是以 php 8.3 的版本為例說明,當然你可以自行決定要安裝的版本。

# 先查看要安裝的版本資訊 brew info php@8.3 # 安裝 brew install php@8.3
# 在 apache 的設定檔,放入下式 LoadModule php_module /opt/homebrew/opt/php@8.3/lib/httpd/modules/libphp.so <FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch> # 設定索引檔 DirectoryIndex index.php index.html

PHP 的設定檔位於 /opt/homebrew/etc/php/8.3/ 裡面。

# 若要使用 php 指令,可以將下兩行放入用戶設定檔 (.zshrc) 裡 export PATH="/opt/homebrew/opt/php@8.3/bin:$PATH" export PATH="/opt/homebrew/opt/php@8.3/sbin:$PATH"

在根目錄 /opt/homebrew/var/www 寫一支 phpinfo() 檔測試看看。

mysql 8.0

# 先查看要安裝的版本資訊 brew info mysql@8.0 # 安裝 brew install mysql@8.0 # 啟動服務 brew services start mysql@8.0

2018-10-18

使用 localhost 測試 Facebook login

2018-10 開始 Facebook login 強制使用 HTTPS 了,若要在 localhost 測試也是得用 HTTPS 才行。以下的參考連結說明 MAMP 的作法:
https://gist.github.com/jfloff/5138826

Facebook login 以前做過幾次,都是針對活動網站的,這次也不例外。一陣子沒做了,想說依照官方範例,應該不會有太大問題,但結果還是卡了一兩個小時。以下列出卡到的點:

1. 在設定 Facebook app 時,在「設定」〉「基本資料」,「應用程式網域」和「網站網址」的域名請一致。(設定介面經常在變,規則也是)

2. 在「Facebook 登入」〉「設定」裡,「對重新導向 URI 使用 Strict 模式」現在預設是設定為開啟,而且不能變更。所以一定要在「有效的 OAuth 重新導向 URI」填寫正確的 redirect uri。

3. 使用 facebook/graph-sdk 時,可以直接 copy sample code 去改,但記得在 login.php 和 fb-callback.php 裡都要先以 session_start() 啟動 session 功能。因為 FacebookRedirectLoginHelper 的 CSRF 是寫在 session 裡的。



2018-06-04

跨埠存取 cross ports

筆記:
  一台主機同時跑 apache/php (port: 80) 和 node/express/react (port: 3000)
  react 要呼叫 php api 時,同時要傳遞 cookie 的情況
  1. apache/php 的 Access-Control-Allow-Origin 要指定,不可以是 wildcard (*)。
  2. apache/php 的 Access-Control-Allow-Credentials 設定為 true。
  3. react 發 ajax 時,withCredentials要設定為 true。

2015-04-17

在 Mac 上昇級 PHP cli 版本的另一種方式

最近因為 laravel 以 Mac 使用 PHP cli 時,發現 Mac 內附的 PHP cli 沒有 Mcrypt extension。依照 Apple 官方的做法是下載原始碼重新編譯,常常是在 make install 過程得到一堆 warnings 然後就卡住了。

這裡的方式是直接安裝 MAMP 免費版,MAMP 3 本身就包含數個版本的 PHP,包含 PHP 5.5 及 PHP 5.6。

/Applications/MAMP/bin/php/php5.5.18/bin/php -m

在 terminal 執行上式,可以得知 MAMP 所內附的 PHP 5.6 cli 包含了哪些 modules。

我使用的 Shell 是 ZSH,所以編輯 ~/.zshrc ,最後面加入下式

export PATH="/Applications/MAMP/bin/php/php5.5.18/bin:$PATH"

儲存 .zshrc 後,離開 terminal,再進入就可以使用較新版本的 PHP cli 了。

2013-12-18

最近遇到 Silex 之 Built-in Service Providers 的問題

Silex 是 PHP 的一種微框架。使用 Silex 而沒有選用 Slim 的原因是 Silex 的肥版內置了常用的功能, 而且 Silex 是 Symfony2 相關的專案。

目前裡面的 Twig 和 Doctrine DBAL 是用得還滿開心的, 但 Session 和 Swiftmailer 就用不太習慣, 或遇到狀況。

寄 mail 的功能, 個人長時間習慣使用 PHPMailer。Swiftmailer 寄未認證信時, 常收不到; PHPMailer 至少會在垃圾郵件中找到。

Session 的問題是 Silex 使用 SessionServiceProvider, 並非 PHP 原先內建的 $_SESSION功能。在混用 Securimage 做 captcha 功能時, 由於 Securimage 使用的是內建的 $_SESSION, 而造成 SessionServiceProvider 無法啟用。
RuntimeException: Failed to start the session: already started by PHP ($_SESSION is set).
後來的解決方式是乾脆 把 SessionServiceProvider 給關了, 直接使用 $_SESSION。



2013-11-12

psr-0 是什麼意思呢?

使用 Composer 時, 在設定檔的 json 常看到 autoload 設定 psr-0。
psr-0 網路上已經有人寫中文說明囉

2013-08-04

Yii 在網址列隱藏 index.php

Yii 在網址列隱藏 index.php
參考 http://www.yiiframework.com/wiki/214/url-hide-index-php/

.htaccess 檔的內容使用
RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php

config/main.php 修改內容
'urlManager'=>array(
    'urlFormat'=>'path',
    'rules'=>array(
      '<controller:\w+>/<id:\d+>'=>'<controller>/view',
      '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
      '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
    ),
    'showScriptName'=>false,
    'caseSensitive'=>false,
),

2013-07-23

Yii 筆記 2 (CRUD)

在 MySQL 建立資料庫和資料表。資料庫連線設定在 protected\config\main.php 的 application components 內,將其設定為 MySQL。

使用 gii 的 Model Generator 建立 Model 檔,欄位填入 Model 類別名及對應的資料表名稱。

使用 gii 的 CRUD Generator 建立 CRUD,欄位填入 Model 類別名及欲新增的 Controller ID。建立之後,新增一個 Controller 類別檔,並在 View 的子目錄裡新增數個 View 內容檔。

表單欄位驗證設定位於 Model 類別的 rules() 方法裡。格式:
array('屬性列表', '驗證器', ...其它設定選項);

驗證器:
boolean:  CBooleanValidator, 布林值 true 或 false。
captcha:  CCaptchaValidator, 圖形驗證碼。
compare:  CCompareValidator, 判斷兩欄位的值是否相等。
email:    CEmailValidator, 有效的 e-mail address。
date:     CDateValidator, 有效的時間值。
default:  CDefaultValueValidator, 是否為預設值。
exist:    CExistValidator, 在資料表中是否已存在。
file:     CFileValidator, 檔案欄位。
filter:   CFilterValidator, 使用 filter 轉換。
in:       CRangeValidator, 某範圍的值。
length:   CStringValidator, 限定資料長度。
match:    CRegularExpressionValidator, 符合某 regular expression。
numerical:CNumberValidator, 數值。
required: CRequiredValidator, 必填欄位。
type:     CTypeValidator, 特定類型的資料。
unique:   CUniqueValidator, 資料表中的唯一資料。
url:      CUrlValidator, 有效的網址格式。

2013-07-21

Yii 筆記 1 (建立 webapp)

下載 yii 並解壓縮到 web server 的 DocumentRoot。以 Yii 的 requirements 檢查環境是否符合需求 http://localhost/yii-1.1.13/requirements/

利用 yiic 建立 webapp
c:\wamp\www\yii-1.1.13\framework>yiic webapp .\..\..\yiitest01

建立的 webapp 並沒有包含 Yii framework, 可以將 c:\wamp\www\yii-1.1.13\framework 複製到 yiitest01/ 裡。然後修改 index.php 裡 $yii 的 framework 路徑。

到 protected/config/main.php 開啟 gii module 設定
 'modules'=>array(
  'gii'=>array(
   'class'=>'system.gii.GiiModule',
   'password'=>'密碼',
   // If removed, Gii defaults to localhost only. Edit carefully to taste.
   'ipFilters'=>array('127.0.0.1','::1'),
  ),
 ),

連到 http://localhost/yiitest01/index.php?r=gii 輸入密碼後,可以看到 gii 預設的功能選單,包含:Controller Generator、Crud Generator、Form Generator、Model Generator、Module Generator。

點選 Controller Generator,在 Controller ID 欄填入 message,Action IDs 欄填入 hello(預設為 index),接著按 "preview" 按鈕,將產生兩個檔案:
controllers\MessageController.php
views\message\hello.php
點按 "Generate" 按鈕,以產生檔案。

點按 "try it now" 時,由於沒有 index action 所以會得到 404
http://localhost/yiitest01/index.php?r=message    // 得到 404
http://localhost/yiitest01/index.php?r=message/hello    // 得到正常頁面

查看 MessageController.php
class MessageController extends Controller
{
    public function actionHello()
    {
        $this->render('hello');
    }
}

也可以設定某個 action 為 default action
public $defaultAction = 'hello';

在 View 裡,變數對應的關係:
$this    // controller object
$this->id    // controller id
$this->action->id    // action id
echo CHtml::link('連結字串', array('控制器/動作')); // 顯示連結

2013-06-07

遠端除錯 FarLog 修正

FarLog 修正,主要是讓訊息可以依照時間排序。舊文章: AIR for iOS 實機測試時的遠端除錯 FarLog
PHP 簡單三個檔: index.php (顯示), log.php (接收) 和 clear.php (清除)。log.php 接收資料記錄到文字檔裡,由 index.php 顯示文字檔內容。
log.php
<?php
if(isset($_REQUEST['log'])) {
  $fp = fopen('log.txt', 'a+');
  fwrite($fp, $_REQUEST['log'] . "\n");
  fclose($fp);
}

index.php
<?php
$filename = 'log.txt';
$fp = @fopen($filename, 'r'); // Open the file

if ($fp) {
  // Add each line to an array
  $array = explode("\n", fread($fp, filesize($filename)));
  // assoc array
  foreach($array as $v) {
    $ar = explode(' : ', $v );
    $assoc_ar[$ar[0]] = $ar[1];
  }

  echo '<meta charset="UTF-8"><pre>';
  ksort($assoc_ar, SORT_NUMERIC); // sort
  foreach($assoc_ar as $k=>$v) {
    echo $k . ' -> ' . $v . "\n";
  }
  echo '</pre>';     
}

clear.php
<?php
unlink('log.txt');

AS 的部份使用 lin.shinder.utils.FarLog 類別的 log() 靜態方法,沒有變更動。

2010-11-22

在 PHP 中使用 SQLite3

很早就知道 PHP5 內建 SQLite 的功能,但是一直沒在 PHP 上使用 SQLite,原因無它「有 MySQL 幹嘛用 SQLite」。
Adobe AIR 上的是 SQLite3,Firefox 的外掛 SQLite Manager 也(只)支援 SQLite3,搭配起來還蠻方便的。
最近有個案子是要做多國語言的展示平台(當然是用 Flash 做囉),要讓管理人員(不會是我)上平台的內容。問題出在那台機器可能沒有網路,就算有網路,頻寬也可能會是個問題,所以要做單機的版本。
展示端無庸置疑 Adobe Flash/AIR 是個好選項,但內容管理用 AIR 就顯得麻煩。為了方便更新內容(拷貝/貼上),目前考慮使用 PHP + SQLite,而把 MySQL 排除在外。

PHP 目前最新的版本是 5.3.X,我租用的 PHP 空間為 5.1.6,雖然這個專案不會用到租用的空間,但為了可以通用,就會以 5.1.6 為預設版本。
用了 PHP5 的 SQLite 才知道原來它的版本是2。PHP 5.1.6 要使用 SQLite3 必須透過 PDO。PHP 5.3 之後的版本才有直接支援 SQLite3 的類別。SQLite2 有啥不好?其實沒什麼不好,只是個人用慣 SQLite Manager 了,而且用舊版心中總會掛念它是舊版,若要用新版的功能時,可能就悔不當初 :P

2010-11-20

承上篇「無法使用phpMyAdmin時的DB資料備份及回復」

sqlbuddy 試用了一下, 功能雖然較 phpMyAdmin 簡單許多, 但其實已經很夠用了 :)

2010-09-03

無法使用phpMyAdmin時的DB資料備份及回復

在某些情況,無法使用 phpMyAdmin,資料庫操作時都會挷手挷腳。
資料備份可以使用 Old Guy Mybackup,只有一個檔案,加密碼設定一下連線帳號資料,再用瀏覽器連一下就 OK 了,很方便。
回復資料的話,用 BigDumpbriian 的介紹阿修的介紹

2010-06-09

在 App Engine 上執行 PHP

Google App Engine 目前只支援 Java 和 Python,支援 Java 就有許多好玩的東西。Quercus 是 Caucho 用 Java 實現的 PHP 解譯引擎,在 Java 環境就可以執行。最早,webdigi 就弄了個 Demo,後來 Quercus 官網也弄了個範例。以下是個人實作的方式:

2010-03-26

新作:FLASH+PHP資料庫網站開發設計

個人新作「FLASH+PHP資料庫網站開發設計」出版了,感謝舊雨新知的支持!

個人新作「FLASH+PHP資料庫網站開發設計」出版
試讀「第6章」18頁

出版公司書籍介紹
博客來
金石堂
建議:老話一句,一本書是無法滿足所有人需求的,請先到實體書店翻閱,符合需求再購買!

2009-08-03

PHP 的上傳設定

PHP 的上傳設定除了修改 upload_max_filesize 外
memory_limit, max_execution_time, post_max_size 也要適當修改
通常 memory_limit > post_max_size > upload_max_filesize

另外, Apache 的上傳控制是 LimitRequestBody

2008-06-21

FileReference 上傳後得知檔案大小

上傳圖檔時, 同時上傳資料, 可以參考之前舊文: FileReference 上傳圖檔

利用偵聽 uploadCompleteData (DataEvent.UPLOAD_COMPLETE_DATA) 事件即可解決

Frame Actions
var uploadURL:String = "upload_test.php";
var req:URLRequest = new URLRequest(uploadURL);
var file:FileReference = new FileReference();

// 設定偵聽器
file.addEventListener(Event.SELECT, myFileSelect);
file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA , myUploadCompleteData);

// 瀏覽上傳的檔案
file.browse([new FileFilter("Images", "*.jpg;*.gif;*.png")]);

// 選擇所欲上傳的圖檔後
function myFileSelect(e:Event):void{
file.upload(req);
}
// 上傳完成後
function myUploadCompleteData(e:DataEvent):void{
var data:String = e.data as String;
trace(data);
var filename = data.split('::')[0];
// 載入圖片
var picReq:URLRequest = new URLRequest(filename);
var pic:Loader = new Loader();
pic.load(picReq);
pic.y = 20;
this.addChild(pic);
// 秀出回傳的字串
var tf:TextField = new TextField();
tf.autoSize = 'left';
tf.text = data;
this.addChild(tf);
}

PHP
<?php
// 圖檔上傳後所欲存放的目錄
$up_dir = "./imgs/";
// 若目錄不存在, 則建立之
if(!is_dir($up_dir))
mkdir($up_dir, 0755);
// 取得上傳檔案的副檔名
$pos = strrpos($_FILES["Filedata"]["name"], ".");
if ($pos === false) {
$ext = "";
}else{
$ext = substr($_FILES["Filedata"]["name"], $pos);
}
// 檔案大小 bytes
$size = $_FILES['Filedata']['size'];
// 以隨機的字串為檔名
$uniq = md5(uniqid(rand(), true));
$up_file = $up_dir . $uniq . $ext;
// 將檔案放到設定的目錄內
move_uploaded_file($_FILES["Filedata"]["tmp_name"], $up_file);
chmod($up_file, 0777);

echo $up_file . '::' . $size;
?>

2008-06-18

透過 ActionScript 產生 PDF

Flash 8 / ActionScript 2 Version: blazePDF v2 component (要付費)

ActionScript 3 Open-Source PDF Library: AlivePDF

Neo's blog 整理的 [PHP] 免費好用的 PDF Library 大搜集

2008-06-04

PHP 使用 JSON 和 AS3 溝通

JSON 常用在 AJAX 的資料交換上,其實也可以用在 SWF<->PHP 上。
PHP5有內建 JSON 的函式;PHP4沒有,但可以用 PEAR 的 JSON 類別
AS3 則可以用 as3corelib 裡的 JSON 類別。
以下是將DB資料轉換成JSON的例子。
mysql2json4.php
/*** shinder.lin@gmail.com
for PHP4
*/
require_once("JSON.php");
function mysql2json4($sql) {
if(is_string($sql)) {
$query = mysql_query($query) or die(mysql_error());
} else {
$query = $sql;
}

$ar = array();
if($total = mysql_num_rows($query)) {
while($row = mysql_fetch_assoc($query)) {
$obj = array();
foreach($row as $key => $value) {
$obj[ $key ] = $value;
}
array_push($ar, $obj);
}
mysql_data_seek($query, 0);
}

$json = new Services_JSON();
return $json->encode($ar);
}
?>

test_mysql2json4.php
require("mysql2json4.php");

mysql_connect("localhost", "root", "");
mysql_select_db("test");
mysql_query("SET NAMES 'utf8'");
$q = mysql_query("select * from ctest");
echo mysql2json4($q);
?>

test_json.fla frame actions:
import  com.adobe.serialization.json.*;

var ur:URLRequest = new URLRequest("http://localhost/json_test/test_mysql2json4.php");
var ul:URLLoader = new URLLoader();
ul.addEventListener(Event.COMPLETE, onComplete);
ul.load(ur);

function onComplete(evt:Event) {
trace(ul.data);
var o:Object = JSON.decode(ul.data);
QopDump.echo(o);
}



資料傳給 PHP
test_json_insert4.php
require_once("JSON.php");

$raw = $GLOBALS["HTTP_RAW_POST_DATA"];

$json = new Services_JSON();
$ar = (array) $json->decode($raw);

mysql_connect("localhost", "root", "");

mysql_select_db("test");
mysql_query("SET NAMES 'utf8'");
// watch out for sql injection
$sql = sprintf("INSERT INTO `ctest` (`sno`, `name`, `phone`) VALUES (NULL, '%s', '%s')", $ar['name'], $ar['phone']);
echo (bool) mysql_query($sql);
?>

test_json_submit.fla frame actions:
import  com.adobe.serialization.json.*;

var ur:URLRequest = new URLRequest("http://localhost/json_test/test_json_insert4.php");
ur.method = URLRequestMethod.POST;
var ul:URLLoader = new URLLoader;

submit_btn.addEventListener(MouseEvent.CLICK, onSubmit);

function onSubmit(evt:MouseEvent):void {
var obj:Object = {name:name_ti.text, phone:phone_ti.text};
var str:String = JSON.encode(obj);
ur.data = str;
ur.contentType = "text/plain";
ul.load(ur);
// trace(str);
}

ul.addEventListener(Event.COMPLETE, onComplete);

function onComplete(evt:Event) {
info_ta.text = ul.data;
}

相關檔案下載

2008-03-10

在 CodeIgniter 裡建立 SabreAMF 的 gateway

承上一篇 結合 CodeIgniter 和 SabreAMF
接著是建立 gateway, 請參考 Using Flex 2 RemoteObject and SabreAMFGetting started with SabreAMF 的作法。
我們會將 gateway 放在 Controllers 裡。Server side remoting 程式則是放在 Models 裡。
在 ci_project/system/application/controllers/ 新增檔案 gateway.php
<?php
class Gateway extends Controller {
function Gateway()
{
parent::Controller();
}

function index()
{
require_once('SabreAMF/CallbackServer.php');
try {
$callbackServer = new SabreAMF_CallbackServer();
$callbackServer->onInvokeService = array($this, 'invokeService');
$callbackServer->exec();
}catch(Exception $e){
echo $e->getMessage();
}
}

function invokeService($service, $method, $data) {
$modelPath = str_replace( '.', '/', $service);
$this->load->model($modelPath, 'amf_model');
return call_user_func_array( array( $this->amf_model, $method ), $data );
}
}
?>

測試的 Models 放在 ci_project/system/application/models/test/test_model.php
<?php
class Test_model extends Model
{
function Test_model()
{
parent::Model();
}

function myMethod($d1, $d2)
{
$ret = array(
array( 'ID' => $d1, 'name' => 'okok', 'phone' => $d2 ),
array( 'ID' => '35712', 'name' => 'Esbd V. Mb', 'phone' => '235-4263' ),
array( 'ID' => '46823', 'name' => 'Ftce W. Nc', 'phone' => '346-5374' ),
);
return $ret;
}
}
?>

Flash CS3 AS3 的 client 測試
import fl.data.DataProvider;
var nc:NetConnection = new NetConnection();
//nc.objectEncoding = ObjectEncoding.AMF3;

var onResult:Function = function(result:Object) {
QopDump.echo(result);
dg.dataProvider = new DataProvider(result);
};
var onStatus:Function = function(info:Object) {
QopDump.echo(info);
};
var responder:Responder = new Responder(onResult, onStatus);
nc.connect("http://localhost/ci/?/gateway");

nc.call("test.Test_model.myMethod", responder, ["888", "666"]);

Flex 的 client 測試
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:RemoteObject id="ro"
destination=" "
endpoint="http://localhost/ci/?/gateway"
source="test.Test_model"
result="resultHandler( event )"
fault="faultHandler( event )">
</mx:RemoteObject>
<mx:Script>
<![CDATA[
import mx.rpc.events.*;
import mx.controls.Alert;
import mx.rpc.*;

private function load():void {
ro.myMethod('first','123-456789');
}
private function resultHandler( event:ResultEvent ):void {
Alert.show( QopDump.go(event.result) );
dg.dataProvider = event.result;
}
private function faultHandler( event:FaultEvent ):void {
Alert.show( event.toString() );
}
]]>
</mx:Script>
<mx:Button click="load()" label="Load" />
<mx:DataGrid id="dg" />
</mx:Application>

FB 留言