首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Elgg 框架實體圖示儲存與自定義圖示 URL 鉤子機制詳解

     編輯:PHP 相關知識

Elgg 是一個開源社交網路引擎,其實體系統提供靈活的圖示處理機制。本文深入解析 Elgg 實體圖示的儲存流程、檔案命名規則、目錄結構,以及如何透過 Plugin Hook 自定義圖示 URL,適用於 Elgg 2.x/3.x/4.x 開發者。

實體圖示儲存流程

當實體(如 Activity 類別繼承 ElggObject)建立時,若上傳了圖示檔案,系統會執行以下流程:

<?php
// 典型儲存邏輯(簡化自原始碼)
if (isset($_FILES['icon']) && substr_count($_FILES['icon']['type'], 'image/')) {
    $prefix = "activity/{$activity->guid}";
    $filehandler = new ElggFile();
    $filehandler->owner_guid = $activity->owner_guid;
    $filehandler->setFilename($prefix . ".jpg");
    $filehandler->open("write");
    $filehandler->write(get_uploaded_file('icon'));
    $filehandler->close();

    // 生成多種尺寸縮圖
    $sizes = [
        'tiny'   => [25, 25, true],
        'small'  => [40, 40, true],
        'medium' => [100, 100, true],
        'large'  => [200, 200, false],
    ];

    foreach ($sizes as $suffix => [$w, $h, $crop]) {
        $resized = get_resized_image_from_existing_file(
            $filehandler->getFilenameOnFilestore(), $w, $h, $crop
        );
        if ($resized) {
            $thumb = new ElggFile();
            $thumb->owner_guid = $activity->owner_guid;
            $thumb->setMimeType('image/jpeg');
            $thumb->setFilename("{$prefix}{$suffix}.jpg");
            $thumb->open("write");
            $thumb->write($resized);
            $thumb->close();
        }
    }
}
?>

檔案儲存目錄結構

Elgg 使用雜湊分佈目錄避免單一目錄檔案過多:

// 使用者 GUID 為 123456 時
// 目錄結構:{dataroot}/123/45/6/
// 檔案命名:{prefix}{size}.jpg
// 例如:activity/789tiny.jpg → 實際路徑
// {dataroot}/123/45/6/activity/789tiny.jpg

ElggFile::getFilenameOnFilestore() 返回完整檔案系統路徑,供 GD/Imagick 處理。

圖示 URL 獲取機制:Plugin Hook 系統

Elgg 核心不直接產生圖示 URL,而是透過事件觸發機制:

<?php
// Elgg 核心 entities.php 簡化邏輯
public function getIcon($size = 'medium') {
    // ...
    $url = $this->getIconURL($size);
    return $url;
}

public function getIconURL($size = 'medium', $params = []) {
    $url = $this->getDefaultIconURL($size); // 預設 URL
    // 觸發鉤子允許外掛修改 URL
    $url = elgg_trigger_plugin_hook('entity:icon:url', $this->getType(), [
        'entity' => $this,
        'size' => $size,
        'params' => $params,
    ], $url);
    return $url;
}
?>

自定義圖示 URL 實作步驟

1. 在外掛 start.php 註冊鉤子

<?php
// mod/your_plugin/start.php
elgg_register_plugin_hook_handler('entity:icon:url', 'object', 'your_plugin_activity_icon_url');

function your_plugin_activity_icon_url($hook, $type, $returnvalue, $params) {
    $entity = $params['entity'];
    $size = $params['size'];
    
    // 僅處理 Activity 子類型
    if ($entity->getSubtype() !== 'activity') {
        return $returnvalue;
    }

    // 自定義邏輯:例如從 CDN 取圖、加簽名 URL、特定尺寸重導向
    $guid = $entity->guid;
    $cdnBase = 'https://cdn.example.com/activity-icons/';
    
    // 檢查檔案是否存在(可選,視效能需求)
    // $exists = check_cdn_file_exists("{$cdnBase}{$guid}/{$size}.jpg");
    
    return "{$cdnBase}{$guid}/{$size}.jpg";
}
?>

2. 進階:根據實體狀態動態決定圖示

<?php
function your_plugin_activity_icon_url($hook, $type, $url, $params) {
    $entity = $params['entity'];
    $size = $params['size'];
    
    if ($entity->getSubtype() !== 'activity') return $url;
    
    // 範例:草稿狀態顯示預設圖示,發布後顯示真實圖示
    if ($entity->status === 'draft') {
        return elgg_get_simplecache_url('graphics/default_activity_draft.png');
    }
    
    // 範例:私有活動加簽名 URL 防止熱連結
    if ($entity->access_id === ACCESS_PRIVATE) {
        return your_plugin_sign_url("{$url}?t=" . time());
    }
    
    return $url;
}
?>

3. 完全控制:實作 ElggEntity::getIconURL() 覆寫(不推薦)

若需求極度特殊,可在實體類別覆寫方法,但會失去鉤子擴充性:

<?php
class Activity extends ElggObject {
    public function getIconURL($size = 'medium', $params = []) {
        // 完全自定義邏輯,不觸發核心鉤子
        return "https://my-cdn.com/activities/{$this->guid}/{$size}.webp";
    }
}
?>

常見問題與除錯

問題原因解決
圖示不顯示/404檔案未正確寫入資料目錄檢查 $CONFIG->dataroot 權限、ElggFile::open() 回傳值
縮圖未生成GD/Imagick 未安裝或記憶體不足安裝 php-gd 或 php-imagick,調整 memory_limit
鉤子不生效優先級/註冊順序問題使用 elgg_register_plugin_hook_handler(..., $priority) 調整優先級(預設 500)
快取導致舊圖示SimpleCache/瀏覽器快取更新實體時呼叫 $entity->invalidateCache(),或 URL 加版本參數

效能優化建議

  1. CDN 整合:鉤子回傳 CDN URL,靜態資源卸載至邊緣節點。
  2. WebP 格式支援:儲存時同步生成 WebP,鉤子根據 $_SERVER['HTTP_ACCEPT'] 回傳最佳格式。
  3. 預簽名 URL:私有圖示使用 S3 預簽名 URL,避免 PHP 代理流量。
  4. 非同步縮圖:大量上傳時,將縮圖生成推入佇列(Gearman/Redis Queue),即時回傳預設圖示。

版本差異提醒

  • Elgg 2.x:使用 elgg_register_plugin_hook_handler(),鉤子名稱 entity:icon:url。
  • Elgg 3.x/4.x:同上,但建議使用服務容器註冊:$services->hooks->registerHandler('entity:icon:url', 'object', $callable)。
  • Elgg 4.x+:支援 PSR-14 事件分派器,可改用 EventDispatcher 介面。

總結

Elgg 實體圖示系統採用「儲存時生成多尺寸」+「讀取時透過 Hook 動態決定 URL」的解耦設計。開發者應善用 entity:icon:url 鉤子實現 CDN 整合、權限控制、格式協商等進階需求,而非直接修改核心或覆寫實體方法。理解檔案命名規則({type}/{guid}{size}.jpg)與資料目錄分佈邏輯,有助於除錯與遷移。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved