Bearweb架构
Bearweb CMS是一个数据库驱动的架构。本文将展示其架构于核心模组:站点地图、会话控制、用户管理。
CMS, 内容管理系统, 数据库驱动, 架构, 站点地图, 会话控制, 用户管理
--by @ Feb 2, 2026Index
代码风格
文件bearweb.class.php包含进入点和3个模组,包含Bearweb CMS进入点class _Bearweb、站点地图模组class _Bearweb_Site、会话模组class _Bearweb_Session、用户模组class _Bearweb_User。不要修改bearweb.class.php。
在index.php里,你需要扩展进入点为Bearweb类,以及3个模组为Bearweb_Site、Bearweb_Session、Bearweb_User。你可以在扩展后的类中重载类方程和变量。
因为Bearweb CMS是数据库驱动的,你将需要为每一个模组指定其数据库。
下面的例子展示了index.php中扩展会话模组,重载会话令牌的cookie名和有效期,指定会话数据库:
class Bearweb_Session extends _Bearweb_Session {
const CookieSID = 'SessionID';
const CookieKey = 'SessionKey';
const Expire = 7 * 24 * 3600;
public static function init(): void {
try { static::$db = new PDO('sqlite:./bw_session.db', null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 10, #10s waiting time should be far more than enough
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]); } catch (Exception $e) { throw new BW_DatabaseServerError('Fail to open DB: '.$e->getMessage(), 500); }
}
}
Bearweb CMS使用PHP前端于SQLite后端。Bearweb CMS使用int、string、array(包括数组和对象)数据类型,这些类型都被PHP支持,但是array作为例外不被SQLite支持。因此,一个PHP的array将会被转化为JSON并保存在string中,再被写入数据库。读出反之。
错误处理
Bearweb的模组和模板在执行期间可以抛出Bearweb Exception类BW_Error,并被Bearweb进入点类Bearweb捕捉。当错误发生(无论是服务器出错还是客户端甩锅),Bearweb进入点类会讲错误记录在Apache2日志中,并执行错误页面模板。
The relationship of BW_Error class family is given below:
-
Exception- PHP原生错误类。(不要直接使用基础类)-
BW_Error- Bearweb基础错误类。(不要直接使用基础类)-
BW_ServerError- 服务端导致的错误(不要直接使用基础类)BW_WebServerError- 服务器前端错误,例如错误配置、丢失模板文件。BW_DatabaseServerError- 服务器数据库错误,例如无法连接到数据库、无法读写数据库、数据条件错误(例如唯一键冲突)。BW_ExternalServerError- 外部服务器错误,例如无法读写对象储存服务器、无法连接令牌登录验证服务器。
-
BW_ClientError- 客户端错误。例如读取不存在的URL(404)、错误密码、错误表单格式。
-
-
开发者
BW_Error(string $message, int $code) - 抛出错误
使用throw BW_Error(string $message, int $code)来终止当前执行的模组或模板,并让Bearweb CMS调用错误页面模板。其中:
message- 阐述错误信息。code- 错误对应的HTTP码。
$e->getMessage(): string - 获取错误信息
和PHP原生Exception类相似,使用$e->getMessage(): string来获取错误信息;或使用echo $e;来打印错误信息和其它相关信息,如呼叫栈。
举例:
try {
...
$db->execute();
} catch (Exception $e) {
throw new BW_DatabaseServerError('Cannot insert into sitemap database: '.$e->getMessage(), 500);
}
...
echo $e->getMessage(); // echo 'BW_DatabaseServerError - Cannot insert into sitemap database: DBMS message'
进入点
当服务器收到一个HTTP请求,底层的Apache2将会执行包含Bearweb CMS的PHP脚本。接下来,Bearweb CMS进入点Bearweb会执行一下操作:
- 初始化3个核心模组:站点地图、会话控制、用户管理。因为Bearweb CMS是数据库驱动的,这一步包括连接到模组的数据库。
- 会话管理。Bearweb CMS将判断该请求所属的会话,或在请求不属于任何会话的情况下创建一个新的会话以便后续请求使用。
- 判断会话绑定的用户。这让Bearweb CMS可以判断请求所有的权限。
- 读取请求的资源(例如网页、图片)或执行请求的API,如果用户有相关的权限的话。
- 执行该资源或API的模板以进一步处理请求。
如果前3步出错,神仙也救不了,Bearweb CMS返回一个致命错误。
当第4、5步错误发生(包括服务端和客户端),Bearweb进入点类将会将错误信息写入Apache2日志并调用错误页模板。
开发者
3个模组都以成员变量的形式包含在Bearweb CMS进入点内Bearweb:
class Bearweb {
protected Bearweb_Session $session;
protected Bearweb_User $user;
protected Bearweb_Site $site;
}
要访问一个模组实例,可以使用$this->module或$BW->module。例如:
echo $this->session->sID; // echo session ID 'AZaz09'
echo $BW->site->url; // echo requested resource's URL 'hello.html'
$this->session->bindUser('John'); // bind current session to user 'John'
出于安全考虑,你可以重载Bearweb::HideServerError为true来隐藏服务端错误。这样,Bearweb CMS将发送一个普通的500 Internal Server Error的HTTP头,不会将实际的错误信息返回给客户端。无论Bearweb::HideServerError设置,实际错误都会被写入Apache2日志。.
会话(Session)控制
会话于交互
一个交互(Transaction)指由客户端发送给服务端的一次HTTP请求和服务端返回给客户端的相应回复。
对于Bearweb CMS来说,一个请求包含了3部分:
- URL:每个请求都必须包含一个URL(HTTP也规定了这一点,HTTP请求的第一行永远是
METHOD URL VERSION,比如GET /bearweb-resource-optimization/zh HTTP/1.1)。这个信息用来向服务器表示该请求的目标资源(或API)。 - 会话令牌:HTTP是无记忆的,也就是说,服务器并不知道是谁发送的请求。为了区分用户,服务器将在第一次交互时生成一个令牌(以cookie的形式)。客户端在接下来的交互中应该包含这个令牌以区分用户。如果客户端禁用了cookie或是选择不发送会话令牌cookie,服务器将会生成一个新的令牌zh。
- 数据:会话可以包括一些数据。主要用于API。= zh
作为一个数据库驱动的架构,Bearweb CMS将每一次交互都记录在数据库中。
对于Bearweb CMS来说,一个会话(Session)包含了来自同一个客户端的请求。
- 如上文所说,使用会话令牌区分交互所属的会话。
作为一个数据库驱动的架构,Bearweb CMS将每一个会话都记录在数据库中。
会话令牌
Bearweb CMS使用客户端cookie和服务器数据库来保存会话令牌。令牌包括3部分:
- 会话ID:一串随机的、非顺序的(所以客户端无法知道服务器访问量)、唯一的字符串。HTTP-only。
- 会话钥匙(key):一串随机的字符串,用于验证会话ID与哈希。
- 上次使用时间戳。只保存在服务端。
会话钥匙对于客户端运行的JavaScript是可见的,可以拿来作哈希计算。一个可疑的JS可以窃取该信息(XSS攻击)来冒充一个会话。为了防止该问题,我们将会话ID设置为HTTP-only。客户端运行的代码将无法看到这个cookie,也就没办法偷走了。但是,这个cookie会被包含在所有发送给服务器的HTTP请求中,允许服务器读取它作为会话令牌验证。
在第一次交互中,客户端的cookie是空的,也就是说,该请求不包含会话令牌。服务器将会生成一个新的会话,将2个cookie发送到客户端,即:会话ID、会话钥匙。
在接下来的交互中,客户端的cookie包含了会话令牌。当客户端发送请求到服务器时,也就包含了会话令牌。服务器通过会话令牌判断客户所属会话。
一个可疑的请求可能包含了伪造的令牌。然而,想要盗取一个会话ID几乎是不可能的(因为是HTTP-only)。当收到的令牌的ID与钥匙不符时,Bearweb CMS将生成并发送一个新的令牌。
如果上次使用时间戳太久了,该会话即过期。将使用一个新的会话。
记录交互与会话控制
当Bearweb CMS收到一个请求时将创建一个Bearweb_Session实例。根据请求提供的会话令牌,Bearweb将执行其一:
- 在会话数据库中更新该会话的
lastuse(上次使用时间戳)为当前(服务器接收到请求时)时间戳。 - 在会话数据库中创建一个新会话。Bearweb将生成并记录会话的
id与key,设置create(创建时间戳)和lastuse(上次使用时间戳)为当前时间。user(会话用户)为''(空字符串,指“游客”)。
Bearweb CMS也会交互数据库中记录:
id- 交互ID。create- 创建时间戳。ip- 客户端IP地址与端口,支持IPv4与IPv6。url- 请求的资源或API的URL。session- 所属会话的ID。log- 交互日志,暂时为空。
以上两项任务将需要写会话数据库与交互数据库,且必须成功。如果任意任务失败,Bearweb CMS将回滚数据库写入信息,并终止执行。
当请求完成并返回结果给客户端后,Bearweb CMS将更新数据库中的交互信息:
log- 提交交互日志。status- 返回的HTTP码。time- 处理使用时间(单位:微秒)。包括等待数据传输的时间(如果发送文件的话,这个数将大到好几秒。甚至几十秒)。该值通过(microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"]) * 1e6得到。memory- 处理占用内存(单位:千字节KiB)。该值通过memory_get_peak_usage(false) / 1024得到。
该任务发生于执行结束前PHP引擎卸载Bearweb_Session实例时,这个任务(非常小概率)可能失败。该失败神仙也救不了,将被忽略,数据库修改将不会生效。
Bearweb_Session类
一个Bearweb_Session类包含以下信息:
| 变量名 | 类型(PHP) | 阐述 | 示例 |
|---|---|---|---|
| sID | public readonly string | 会话ID。 |
|
| sCreate | public readonly int | 会话创建时间。 |
|
| sLastUse | public readonly int | 会话上次使用时间。 |
|
| sUser | public readonly string | 会话绑定用户ID。 |
|
| sKey | public readonly string | 会话钥匙。 |
|
| tID | public readonly string | 交互ID。 |
|
| tCreate | public readonly int | 交互创建时间。 |
|
| tIP | public readonly string | 交互客户端IP地址与端口,可以是IPv4或IPv6地址。 |
|
| tURL | public readonly string | 交互请求的资源或API的URL。 |
|
| tSID | public readonly string | 交互对应会话ID。 |
|
| tLog | public readonly string | 交互日志。调试用。使用$BW->log('Hello world');来打一行log。 |
|
log(string $log): string - 添加一行交互日志
使用$BW->session->log(string $log): string来添加一行交互日志,其中:
log- 信息。return- 添加后的日志全文。
// Log is empty at first
echo $BW->session->log('A'); // echo "\nA"
$BW->session->log('B');
echo $BW->session->log('C'); // echo "\nA\nB\nC"
// At the end, "\nA\nB\nC" will be write to transaction database
日志将在前端缓存,只有在进程结束后再写入数据库。(Write-back策略)
bindUser(string $uid): void - 会话绑定用户
使用$BW->session->bindUser(string $uid): void来绑定会话的用户,其中:
uid- 用户ID。
这个方程将写入用户到数据库。使用该会话令牌的后续请求将使用该用户。
// Transaction at time 1:
echo $BW->session->user['ID']; // echo '', guest, current session has no user bind
$BW->session->bindUser('uid123');
// Transaction at time 2:
echo $BW->session->user['ID']; // echo 'uid123', current session bind to user with ID 'uid123'
// Transaction at time 3:
$BW->session->bindUser(''); //Logout, bind current session back to guest
// transaction at time 4:
echo $BW->session->user['ID']; // echo '', guest, no user bind
该方程可能抛出BW_DatabaseServerError。
updateKey(): string - 更新服务端与客户端的会话钥匙
出于安全考虑,你也许想使用$BW->session->updateKey(): string来生成新的会话钥匙,其中:
return- 新的钥匙。
这个方程将把新的钥匙写入数据库并发送给客户端。后续请求必须使用新的钥匙。
该方程可能抛出BW_DatabaseServerError。
用户(User)管理
判断会话用户
如果一个会话绑定了用户,数据库中该会话将包含该用户的ID。该情况下,Bearweb CMS将查找用户数据库来决定该用户的组。同时,Bearweb还会更新该用户的最后活动时间。
如果会话未绑定用户,用户就是“游客”。
使用用户名和密码通过“登录”请求来绑定会话用户。如果登录成功,Bearweb CMS就会更新会话数据库中的会话用户。该会话的后续交互就会使用这个用户ID与组。
在架构层面,Bearweb CMS只关注请求的用户和组。用户和组决定了用户在访问某个资源时的权限。例如,一个资源只能被所有者和管理员组修改,一个启用访问控制的资源只能被白名单用户和组读取。
密码哈希
虽然使用HTTPS防止网络上第三方看到密码,但密码仍然以明文方式呈现给服务器。服务器端的可以程序将能窃取密码。例如,加载了一个有问题的PHP库。
在保存密码到数据库前使用PHP自带的password_hash()哈希可以防止其它进程通过读数据库窃取密码明文,但仍然无法杜绝服务端在哈希前的密码泄露。
在客户端就进行哈希能够防止密码明文暴露在服务端或在传输过程中。
加盐能够提高安全性。使用动态的盐锦上添花。
Bearweb CMS使用动态加盐来保护密码。
哈希算法为SHA-384,使用JavaScript的window.crypto.subtle.digest('SHA-384', 'password')方程。该方程需要HTTPS。
注册
使用会话钥匙(会话开始时随机生成)作为盐对用户密码的明文(用户键盘输入)加密。
hashedPassowrd = hash(sessionKey + rawPassword);
xhr_register(id, hashedPassowrd);
服务器保存用户数据时将保存会话钥匙为salt、哈希过后的密码为password。
登录
在登录时,客户端首先需要下载上一次哈希时使用的盐来计算出服务器上保存的哈希过后的密码。但是,密码明文在该哈希过后的密码将不会被直接发送,而是通过当前会话钥匙被再次哈希后才发送给服务器。服务器通过数据库中上次哈希后的密码和当前会话钥匙哈希计算验证。
接下来,客户端使用用户输入的密码明文于当前会话钥匙哈希计算新的哈希过后的密码。服务器修改用户数据库使用新的哈希和密码。
oldSalt = xhr_getSalt(id);
oldHashedPassword = hash(oldSalt + rawPassword);
verifyHashedPassword = hash(sessionKey + oldHashedPassword);
newHashedPassword = hash(sessionKey + rawPassword);
xhr_login(id, verifyHashedPassword, newHashedPassword);
可以通过提供新的密码来计算newHashedPassword的方式修改密码。
Bearweb_User类
一个Bearweb_User类包含以下信息:
| 变量名 | 类型(PHP) | 阐述 | 示例 |
|---|---|---|---|
| id | public string | 用户ID。唯一的。区分大小写。 |
|
| name | public string | 用户昵称。这个昵称可以重名。 |
|
| salt | public string | 密码用盐。 |
|
| password | public string | 加盐哈希后的32字节(256-bit)密码。 |
|
| registertime | public int | 创建帐号时间戳。 |
|
| lastactive | public int | 最后活跃时间戳。 |
|
| group | public array | 用户的分组。使用int作为组ID。组0为“管理员”。 |
|
| data | public array | 用户的其它数据。 |
|
| 参数 | 默认 | 可接受类型与例子 |
|---|---|---|
| id | string ''(空字符串) - 无用户名。 |
|
| name | string 'Guest' - 访客昵称/ |
|
| salt | string ':' - 非法盐。你可以通过非法格式来禁用一个用户登录。 |
|
| password | string ':' - 非法密码。你可以通过非法格式来禁用一个用户登录。 |
|
| registertime | Bearweb_User::TIME_CURRENT - 使用当前时间戳。 |
|
| lastactive | Bearweb_User::TIME_CURRENT - 使用当前时间戳。 |
|
| group | array [] - 无分组。 |
|
| data | array [] - 无数据。 |
|
isAdmin(): bool, isGuest(): bool - 用户是否为访客或管理员
要验证一个用户是否为访客或是否为管理员(组0),使用:
echo $BW->user->isGuest() ? 'Register first' : ('Hello old friend '.$BW->user->id);
if($someuser->isAdmin())
show_system_load();
else
throw new BW_ClientError('Access denied', 403);
管理员分组为0。
用户名为''(空字符串)需要特殊考虑。
- 如果指会话的用户为
'',该会话为游客。 - 如果一个资源的所有者为
'',该资源所有者为系统。
validID(string $uid): bool, validPassword(string $pass): bool - 验证用户提交信息格式
要验证用户提交信息格式,使用:
if ( !Bearweb_User::validID($_POST['ID']) || !Bearweb_User::validPassword($_POST['password']) )
throw new BW_ClientError('Bad data format', 400);
query(string $id, int $flag = 0): ?Bearweb_User - 查找用户
使用Bearweb_User::query(string $id, int $flag = 0): ?Bearweb_User来从数据库中查找一个用户,其中:
id- 用户ID。flag- 比特或参数,其中:Bearweb_User::QUERY_UPDATE_LASTACTIVE- 查询前先修改用户lastactive。
return- 一个Bearweb_User实例。如果用户不存在,返回null。
例如:
$user = Bearweb_User::query('John');
echo 'Hello',$user->nickname;
该方程可能抛出BW_DatabaseServerError。
insert(): void, update(): void - 创建或修改用户
要创建或修改一个用户,首先创建一个Bearweb_User实例,并提供用户信息;或是查找一个用户,再修改用户数据。接下来,使用$user->insert()来创建用户,或是$user->update()来修改一个用户。例如:
$user = new Bearweb_User(
id: 'John',
registertime: 114514,
lastactive: 1919810,
... /* Other data */
);
$user->insert(); // 创建用户
$user->update(); // 直接覆盖一个用户(使用该ID)
$user = Bearweb_User::query('John');
$user->nickname = 'John Doe II';
$user->update(); // 修改一个用户的某项数据
该方程可能抛出BW_DatabaseServerError。
站点地图(Sitemap)
网络服务器和文件服务器相似。客户端发送一个包含URL(文件名)、会话令牌(读写权限)、可选额外数据(上传文件)的请求到服务器以下载某个资源(文件内容)。
请求一个资源(例如网页、图片)说白了就是从服务器下载那个文件。
Bearweb CMS使用数据库来储存资源和相关元素据。每一个资源都可以通过URL进行索引。在数据发送给客户端前,元素据可以用于整合访问控制和数据处理。
请求资源
当Bearweb CMS调用一个资源的模板前会:
- 如果该资源不存在,就返回一个HTTP 404 Not Found。终止执行并调用错误模板。
- 访问控制。如果资源定义了
meta.access,只有白名单meta.access中的用户和组才能读取该资源。资源的所有者和管理员永远有读权限。如果用户没有访问权限,终止执行并调用错误模板。 - 重定向。如果资源定义了
meta.r301或meta.r302,就发送HTTP 301或302。终止执行并调用错误模板。 - 缓存控制。如果一个资源没有修改时间戳
modify,该资源就是实时生成的。Bearweb CMS会发送一个随机E-Tag并禁用客户端缓存(比如说,API返回的结果应该表示最新消息)。否则,Bearweb CMS将允许客户端缓存以减少重复请求该资源(比如说,每一张网页都是用相同样式表,可以复用)。 - 按实际需求发送其它HTTP头。
接下来,根据资源的template执行模板,具体参考模板文档。
三级站点地图
固定地图(Fixed map)
可以把一个资源直接写在代码里Bearweb_Site::FixedMap:
const FixedMap = [
'favicon.ico' => ['category' => 'Web', 'create' => 1145141919, 'modify' => 1145141919, 'content' => null, 'aux' => ['mime' => 'image/x-icon']],
'api/dryrun' => ['category' => 'API', 'template' => ['api','general'], 'meta' => ['task' => 'nop']],
...
];
当Bearweb CMS超找一个资源是,会先通过URL作为键查看固定地图。正如其名曰,固定地图保存的资源都是只读的、固定的、永远不会改变的(存废修改代码)。这可以包括样式表、JavaScript文件、图标、API。
使用固定地图速度快且不会出错,因为该资源存在于代码中(程序内存),可以立刻使用。
创建或修改一个可以在固定地图中找到的资源会抛出BW_DatabaseServerError。
数据库
如果在固定地图中找不到该资源,Bearweb CMS就会去找站点地图数据库。
数据库的资源时可被修改的。因此,适合用于保存在网站运行途中需要读写的、用户生成的内容(如文章、图片)。
不过,访问数据库需要读写文件,所以速度会慢一些,且有可能出现执行错误。
文件支持内容
Bearweb CMS不仅支持HTML网页,还支持文件,如图片。
文件可以很大。比如,一张照片可能会好几MB或是好几十MB。所有资源(包括图片等文件)加起来可能会上GBs,全都一股脑存入数据库会导致数据库臃肿低效,很不优雅。
要给数据库减负,我们在数据库中只保存元数据,而大文件的内容将使用外部文件保存。小文件的内容仍然保存在数据库中。
可以参考这一篇文章。
Bearweb_Site类
一个Bearweb_Site类包含以下信息:
| 变量名 | 类型(PHP) | 阐述 | 示例 |
|---|---|---|---|
| url | public string | 资源URL。唯一的。区分大小写。 |
|
| category | public string | 资源分类,用于管理目的,Bearweb CMS不使用这个值。 |
|
| template | public array | 进一步处理这个资源的模板。Bearweb CMS将调用template[0](模板),然后template[0]将调用template[1](子模板)。 |
|
| owner | public string | 资源所有者的用户ID(user id)。只有所有者和管理员(组0)才可以修改这个资源。 |
|
| create | public int | 创建时间戳。 |
|
| modify | public int | 修改时间戳。 |
|
| meta | public array | 资源元素据。包含Bearweb CMS架构与模板使用的可选数据。 |
|
| content | public string | 资源内容。为最小化服务器负载,内容应该是最终输出的内容(对于网页来说,这里应该包含HTML而不是markdown)。如果为null,Bearweb将在资源目录下以url为文件名读取文件。这是为了不在数据库中保存大文件,参考我的博客详述。 |
PHP中
|
| aux | public array | 资源额外素据。包含模板使用的可选数据。 |
|
| 参数 | 默认 | 可接受类型与例子 |
|---|---|---|
| url | string ''(空字符串) |
|
| category | string '' |
|
| template | ['object', 'blob'] - 对象(文件)模板,直接输出内容。 |
|
| owner | string ''(空字符串) - 系统所有资源。 |
|
| create | Bearweb_Site::TIME_NULL (0) - 无实际时间。 |
|
| modify | Bearweb_Site::TIME_NULL (0) - 无实际时间。 |
|
| meta | array [] - 空元数据。 |
|
| content | string ''(空字符串) |
对于文件支持的资源, |
| aux | array [] - 空额外数据。 |
|
access(Bearweb_User $user): bool - 测试用户访问权限
使用$resource->access(Bearweb_User $user): bool来测试用户访问权限,其中:
user- 一个Bearweb_User实例。
返回其中之一:
Bearweb_Site::ACCESS_NONE(0) - 无权读写。Bearweb_Site::ACCESS_RO(1) - 只读。Bearweb_Site::ACCESS_RW(0) - 可读写。
如果一个资源的meta中有定义access,那就是一个启用访问控制的资源。所有者和管理员组用户永远拥有读写权力。对于未启用访问控制的资源,所有的用户和游客都可以读取。对于启用访问控制的资源,只有白名单用户和白名单组才可读取。
validURL(string $uid): bool - 用户提交URL格式检查
要检查用户提交URL格式,使用:
if (!Bearweb_Site::validURL($_SERVER["SCRIPT_URL"])) {
http_response_code(400);
exit('Bad URL');
}
URL的格式要求为:
- 少于128字符长度。
- 只可以使用字母与数字组合
A-Za-z0-9于有限的符号-_:/.。 - 不可以包含
./(自然也不可以包含../)。
query(string $url): ?Bearweb_Site - 查找一个资源
使用Bearweb_Site::query(string $url): ?Bearweb_Site来查找一个资源,其中:
url- 资源URL。return- 一个Bearweb_Site实例。如果资源不存在,返回null。
例如:
$resource = Bearweb_Site::query('hello/world.html');
echo $resource ? $resource->content : '404 Not Found';
Bearweb CMS将首先查找固定地图,再查找数据库。
返回的Bearweb_Site实例中,content可以是:
string- 实际内容。(数据库支持)resource- 文件指针。(文件支持)
content使用PHP getter hook。读取该变量将总会返回实际数据(因为hook将自动执行文件读取)。使用get_mangled_object_vars($resource)['content']来获得原始值。
该方程可能抛出BW_DatabaseServerError。
dumpContent(int $len = -1, bool $header = false): void -直接输出内容
虽然数据库支持的资源和文件支持的资源都可以echo $resource->content输出内容,但这对文件支持的资源并不友好。这将需要首先将内容读入内存中,如果文件过大可能造成内存溢出的问题,例如高清大图和视频文件。
使用$resource->dumpContent(int $len = -1, bool $header = false): void来直接输出内容,避免将文件支持的资源读入内存,其中:
len- 输出最多len字节。该参数对数据库支持的资源无效。header- 如果为true,则同时输出Content-LengthHTTP头。
例如:
$resource = Bearweb_Site::query('hello/world.png');
$resource->dumpContent(-1, true);
该方程为对象(文件)模板优化。
getContentLength(): int - 获得内容大小
使用$resource->getContentLength(): int来获得内容大小,对数据库支持的资源和文件支持的资源都有效。
为了原子性,考虑使用$resource->dumpContent(-1, true)来同时输出内容和长度头。
insert(): void, update(): void, upsert(): void - 创建或修改资源
要创建或修改一个资源,首先创建一个Bearweb_Site实例,并提供资源信息;或是查找一个资源,再修改资源数据。接下来,使用$resource->insert()来创建一个资源,或是$resource->update()来修改一个资源,或是$resource->upsert()创建或修改一个已知的资源。例如:
$resource = new Bearweb_Site(
url: 'hello/world.html',
content: '...',
... /* Other data */
);
$resource->insert(); // 创建一个资源,如果已存在则会失败
$resource->update(); // 覆盖一个已存在的资源,如果不存在就会失败
$resource->upsert(); // 创建一个资源,如果已存在就修改
$resource = Bearweb_Site::query('John');
$resource->content = 'Foo';
$resource->modify = Bearweb_Site::TIME_CURRENT;
$resource->update(); // 修改一个已存在的资源的特定数据
如果content的体积过大(默认分界线为100kB,可以通过Bearweb_Site::Size_FileBlob设置),那么content将被保存在文件中而不是数据库中。该情况下,数据库中content值将为null。
你只要把数据字节交给这几个方程就好了。不要手动创建文件,Bearweb CMS内部逻辑会处理好。
不要创建或修改固定地图中能找到的资源。
该方程可能抛出BW_DatabaseServerError。
delete(): void - 删除一个资源
要删除一个资源,先创建一个Bearweb_Site实例,只需要提供资源URL。然后,使用$resource->delete()来删除那个资源。例如:
$resource = new Bearweb_Site(
url: 'hello/world.html',
... /* Other data will be ignored */
);
$resource->delete();
不要删除固定地图中能找到的资源。
该方程可能抛出BW_DatabaseServerError。