appwrite-php by chiragagg5k/appwrite-agent-skills
npx skills add https://github.com/chiragagg5k/appwrite-agent-skills --skill appwrite-phpcomposer require appwrite/appwrite
use Appwrite\Client;
use Appwrite\ID;
use Appwrite\Query;
use Appwrite\Services\Users;
use Appwrite\Services\TablesDB;
use Appwrite\Services\Storage;
use Appwrite\Services\Functions;
use Appwrite\InputFile;
$client = (new Client())
->setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
->setProject(getenv('APPWRITE_PROJECT_ID'))
->setKey(getenv('APPWRITE_API_KEY'));
$users = new Users($client);
// 创建用户
$user = $users->create(ID::unique(), 'user@example.com', null, 'password123', 'User Name');
// 列出用户
$list = $users->list([Query::limit(25)]);
// 获取用户
$fetched = $users->get('[USER_ID]');
// 删除用户
$users->delete('[USER_ID]');
注意: 所有新代码请使用
TablesDB(而非已弃用的 类)。仅当现有代码库已依赖它或用户明确要求时才使用 。
composer require appwrite/appwrite
use Appwrite\Client;
use Appwrite\ID;
use Appwrite\Query;
use Appwrite\Services\Users;
use Appwrite\Services\TablesDB;
use Appwrite\Services\Storage;
use Appwrite\Services\Functions;
use Appwrite\InputFile;
$client = (new Client())
->setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
->setProject(getenv('APPWRITE_PROJECT_ID'))
->setKey(getenv('APPWRITE_API_KEY'));
$users = new Users($client);
// Create user
$user = $users->create(ID::unique(), 'user@example.com', null, 'password123', 'User Name');
// List users
$list = $users->list([Query::limit(25)]);
// Get user
$fetched = $users->get('[USER_ID]');
// Delete user
$users->delete('[USER_ID]');
Note: Use
TablesDB(not the deprecated class) for all new code. Only use if the existing codebase already relies on it or the user explicitly requests it.
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
DatabasesDatabases$tablesDB = new TablesDB($client);
// 创建数据库
$db = $tablesDB->create(ID::unique(), 'My Database');
// 创建行
$doc = $tablesDB->createRow('[DATABASE_ID]', '[TABLE_ID]', ID::unique(), [
'title' => 'Hello World'
]);
// 查询行
$results = $tablesDB->listRows('[DATABASE_ID]', '[TABLE_ID]', [
Query::equal('title', ['Hello World']),
Query::limit(10)
]);
// 获取行
$row = $tablesDB->getRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]');
// 更新行
$tablesDB->updateRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]', [
'title' => 'Updated'
]);
// 删除行
$tablesDB->deleteRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]');
// 过滤
Query::equal('field', ['value']) // == (始终传递数组)
Query::notEqual('field', ['value']) // !=
Query::lessThan('field', 100) // <
Query::lessThanEqual('field', 100) // <=
Query::greaterThan('field', 100) // >
Query::greaterThanEqual('field', 100) // >=
Query::between('field', 1, 100) // 1 <= field <= 100
Query::isNull('field') // is null
Query::isNotNull('field') // is not null
Query::startsWith('field', 'prefix') // starts with
Query::endsWith('field', 'suffix') // ends with
Query::contains('field', ['sub']) // contains (字符串或数组)
Query::search('field', 'keywords') // 全文搜索 (需要索引)
// 排序
Query::orderAsc('field')
Query::orderDesc('field')
// 分页
Query::limit(25) // 最大行数 (默认 25,最大 100)
Query::offset(0) // 跳过 N 行
Query::cursorAfter('[ROW_ID]') // 游标分页 (推荐)
Query::cursorBefore('[ROW_ID]')
// 选择与逻辑
Query::select(['field1', 'field2']) // 仅返回指定字段
Query::or([Query::equal('a', [1]), Query::equal('b', [2])]) // OR
Query::and([Query::greaterThan('age', 18), Query::lessThan('age', 65)]) // AND (默认)
$storage = new Storage($client);
// 上传文件
$file = $storage->createFile('[BUCKET_ID]', ID::unique(), InputFile::withPath('/path/to/file.png'));
// 列出文件
$files = $storage->listFiles('[BUCKET_ID]');
// 删除文件
$storage->deleteFile('[BUCKET_ID]', '[FILE_ID]');
use Appwrite\InputFile;
InputFile::withPath('/path/to/file.png') // 从文件系统路径
InputFile::withData('Hello world', 'hello.txt') // 从字符串内容
$teams = new Teams($client);
// 创建团队
$team = $teams->create(ID::unique(), 'Engineering');
// 列出团队
$list = $teams->list();
// 创建成员资格 (通过电子邮件邀请用户)
$membership = $teams->createMembership('[TEAM_ID]', ['editor'], email: 'user@example.com');
// 列出成员资格
$members = $teams->listMemberships('[TEAM_ID]');
// 更新成员角色
$teams->updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', ['admin']);
// 删除团队
$teams->delete('[TEAM_ID]');
基于角色的访问控制: 在设置权限时,对所有团队成员使用
Role::team('[TEAM_ID]'),或对特定团队角色使用Role::team('[TEAM_ID]', 'editor')。
$functions = new Functions($client);
// 执行函数
$execution = $functions->createExecution('[FUNCTION_ID]', '{"key": "value"}');
// 列出执行记录
$executions = $functions->listExecutions('[FUNCTION_ID]');
// src/main.php — Appwrite 函数入口点
return function ($context) {
// $context->req->body — 原始请求体 (字符串)
// $context->req->bodyJson — 解析后的 JSON (数组或 null)
// $context->req->headers — 请求头 (数组)
// $context->req->method — HTTP 方法
// $context->req->path — URL 路径
// $context->req->query — 查询参数 (数组)
$context->log('Processing: ' . $context->req->method . ' ' . $context->req->path);
if ($context->req->method === 'GET') {
return $context->res->json(['message' => 'Hello from Appwrite Function!']);
}
$data = $context->req->bodyJson ?? [];
if (!isset($data['name'])) {
$context->error('Missing name field');
return $context->res->json(['error' => 'Name is required'], 400);
}
return $context->res->json(['success' => true]); // JSON
// return $context->res->text('Hello'); // 纯文本
// return $context->res->empty(); // 204
// return $context->res->redirect('https://...'); // 302
};
SSR 应用 (Laravel, Symfony 等) 使用 服务器 SDK 来处理认证。你需要两个客户端:
管理员客户端 — 使用 API 密钥,创建会话,绕过速率限制 (可复用的单例)
会话客户端 — 使用会话 Cookie,代表用户执行操作 (每个请求创建,切勿共享)
use Appwrite\Client; use Appwrite\Services\Account;
// 管理员客户端 (可复用) $adminClient = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') ->setProject('[PROJECT_ID]') ->setKey(getenv('APPWRITE_API_KEY'));
// 会话客户端 (每个请求创建) $sessionClient = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') ->setProject('[PROJECT_ID]');
$session = $COOKIE['a_session[PROJECT_ID]'] ?? null; if ($session) { $sessionClient->setSession($session); }
$account = new Account($adminClient);
$session = $account->createEmailPasswordSession($email, $password);
// Cookie 名称必须是 a_session_<PROJECT_ID>
setcookie('a_session_[PROJECT_ID]', $session['secret'], [
'httpOnly' => true,
'secure' => true,
'sameSite' => 'strict',
'expires' => strtotime($session['expire']),
'path' => '/',
]);
$session = $_COOKIE['a_session_[PROJECT_ID]'] ?? null;
if (!$session) {
http_response_code(401);
exit;
}
$sessionClient->setSession($session);
$account = new Account($sessionClient);
$user = $account->get();
// 步骤 1: 重定向到 OAuth 提供商
$account = new Account($adminClient);
$redirectUrl = $account->createOAuth2Token(
OAuthProvider::GITHUB(),
'https://example.com/oauth/success',
'https://example.com/oauth/failure',
);
header('Location: ' . $redirectUrl);
// 步骤 2: 处理回调 — 交换令牌获取会话
$account = new Account($adminClient);
$session = $account->createSession($_GET['userId'], $_GET['secret']);
setcookie('a_session_[PROJECT_ID]', $session['secret'], [
'httpOnly' => true, 'secure' => true, 'sameSite' => 'strict',
'expires' => strtotime($session['expire']), 'path' => '/',
]);
Cookie 安全性: 始终使用
httpOnly、secure和sameSite: 'strict'来防止 XSS 攻击。Cookie 名称必须是a_session_<PROJECT_ID>。
转发用户代理: 调用
$sessionClient->setForwardedUserAgent($_SERVER['HTTP_USER_AGENT'])来记录最终用户的浏览器信息,用于调试和安全目的。
use Appwrite\AppwriteException;
try {
$row = $tablesDB->getRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]');
} catch (AppwriteException $e) {
echo $e->getMessage(); // 人类可读的错误信息
echo $e->getCode(); // HTTP 状态码 (整数)
echo $e->getType(); // Appwrite 错误类型字符串 (例如 'document_not_found')
echo $e->getResponse(); // 完整的响应体 (数组)
}
常见错误码:
| 代码 | 含义 |
|---|---|
401 | 未授权 — 缺少或无效的会话/API 密钥 |
403 | 禁止访问 — 对此操作权限不足 |
404 | 未找到 — 资源不存在 |
409 | 冲突 — 重复的 ID 或唯一约束冲突 |
429 | 速率限制 — 请求过多,请在退避后重试 |
Appwrite 使用权限字符串来控制对资源的访问。每个权限将一个操作 (read、update、delete、create 或 write,它授予创建 + 更新 + 删除权限) 与一个角色目标配对。默认情况下,除非在文档/文件级别明确设置权限或从集合/存储桶设置继承,否则没有用户具有访问权限。权限是使用 Permission 和 Role 辅助函数构建的字符串数组。
use Appwrite\Permission;
use Appwrite\Role;
$doc = $tablesDB->createRow('[DATABASE_ID]', '[TABLE_ID]', ID::unique(), [
'title' => 'Hello World'
], [
Permission::read(Role::user('[USER_ID]')), // 特定用户可以读取
Permission::update(Role::user('[USER_ID]')), // 特定用户可以更新
Permission::read(Role::team('[TEAM_ID]')), // 所有团队成员可以读取
Permission::read(Role::any()), // 任何人 (包括访客) 可以读取
]);
$file = $storage->createFile('[BUCKET_ID]', ID::unique(), InputFile::withPath('/path/to/file.png'), [
Permission::read(Role::any()),
Permission::update(Role::user('[USER_ID]')),
Permission::delete(Role::user('[USER_ID]')),
]);
何时设置权限: 当你需要按资源进行访问控制时,设置文档/文件级别的权限。如果集合中的所有文档共享相同的规则,请在集合/存储桶级别配置权限,并将文档权限留空。
常见错误:
- 忘记设置权限 — 资源对所有用户 (包括创建者) 都变得不可访问
- 对
write/update/delete使用Role::any()— 允许任何用户,包括未认证的访客,修改或删除资源- 对敏感数据使用
Permission::read(Role::any())— 使资源公开可读
每周安装数
1
代码仓库
首次出现
今天
安全审计
安装于
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1
DatabasesDatabases$tablesDB = new TablesDB($client);
// Create database
$db = $tablesDB->create(ID::unique(), 'My Database');
// Create row
$doc = $tablesDB->createRow('[DATABASE_ID]', '[TABLE_ID]', ID::unique(), [
'title' => 'Hello World'
]);
// Query rows
$results = $tablesDB->listRows('[DATABASE_ID]', '[TABLE_ID]', [
Query::equal('title', ['Hello World']),
Query::limit(10)
]);
// Get row
$row = $tablesDB->getRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]');
// Update row
$tablesDB->updateRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]', [
'title' => 'Updated'
]);
// Delete row
$tablesDB->deleteRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]');
// Filtering
Query::equal('field', ['value']) // == (always pass array)
Query::notEqual('field', ['value']) // !=
Query::lessThan('field', 100) // <
Query::lessThanEqual('field', 100) // <=
Query::greaterThan('field', 100) // >
Query::greaterThanEqual('field', 100) // >=
Query::between('field', 1, 100) // 1 <= field <= 100
Query::isNull('field') // is null
Query::isNotNull('field') // is not null
Query::startsWith('field', 'prefix') // starts with
Query::endsWith('field', 'suffix') // ends with
Query::contains('field', ['sub']) // contains (string or array)
Query::search('field', 'keywords') // full-text search (requires index)
// Sorting
Query::orderAsc('field')
Query::orderDesc('field')
// Pagination
Query::limit(25) // max rows (default 25, max 100)
Query::offset(0) // skip N rows
Query::cursorAfter('[ROW_ID]') // cursor pagination (preferred)
Query::cursorBefore('[ROW_ID]')
// Selection & Logic
Query::select(['field1', 'field2']) // return only specified fields
Query::or([Query::equal('a', [1]), Query::equal('b', [2])]) // OR
Query::and([Query::greaterThan('age', 18), Query::lessThan('age', 65)]) // AND (default)
$storage = new Storage($client);
// Upload file
$file = $storage->createFile('[BUCKET_ID]', ID::unique(), InputFile::withPath('/path/to/file.png'));
// List files
$files = $storage->listFiles('[BUCKET_ID]');
// Delete file
$storage->deleteFile('[BUCKET_ID]', '[FILE_ID]');
use Appwrite\InputFile;
InputFile::withPath('/path/to/file.png') // from filesystem path
InputFile::withData('Hello world', 'hello.txt') // from string content
$teams = new Teams($client);
// Create team
$team = $teams->create(ID::unique(), 'Engineering');
// List teams
$list = $teams->list();
// Create membership (invite user by email)
$membership = $teams->createMembership('[TEAM_ID]', ['editor'], email: 'user@example.com');
// List memberships
$members = $teams->listMemberships('[TEAM_ID]');
// Update membership roles
$teams->updateMembership('[TEAM_ID]', '[MEMBERSHIP_ID]', ['admin']);
// Delete team
$teams->delete('[TEAM_ID]');
Role-based access: Use
Role::team('[TEAM_ID]')for all team members orRole::team('[TEAM_ID]', 'editor')for a specific team role when setting permissions.
$functions = new Functions($client);
// Execute function
$execution = $functions->createExecution('[FUNCTION_ID]', '{"key": "value"}');
// List executions
$executions = $functions->listExecutions('[FUNCTION_ID]');
// src/main.php — Appwrite Function entry point
return function ($context) {
// $context->req->body — raw body (string)
// $context->req->bodyJson — parsed JSON (array or null)
// $context->req->headers — headers (array)
// $context->req->method — HTTP method
// $context->req->path — URL path
// $context->req->query — query params (array)
$context->log('Processing: ' . $context->req->method . ' ' . $context->req->path);
if ($context->req->method === 'GET') {
return $context->res->json(['message' => 'Hello from Appwrite Function!']);
}
$data = $context->req->bodyJson ?? [];
if (!isset($data['name'])) {
$context->error('Missing name field');
return $context->res->json(['error' => 'Name is required'], 400);
}
return $context->res->json(['success' => true]); // JSON
// return $context->res->text('Hello'); // plain text
// return $context->res->empty(); // 204
// return $context->res->redirect('https://...'); // 302
};
SSR apps (Laravel, Symfony, etc.) use the server SDK to handle auth. You need two clients:
Admin client — uses an API key, creates sessions, bypasses rate limits (reusable singleton)
Session client — uses a session cookie, acts on behalf of a user (create per-request, never share)
use Appwrite\Client; use Appwrite\Services\Account;
// Admin client (reusable) $adminClient = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') ->setProject('[PROJECT_ID]') ->setKey(getenv('APPWRITE_API_KEY'));
// Session client (create per-request) $sessionClient = (new Client()) ->setEndpoint('https://<REGION>.cloud.appwrite.io/v1') ->setProject('[PROJECT_ID]');
$session = $COOKIE['a_session[PROJECT_ID]'] ?? null; if ($session) { $sessionClient->setSession($session); }
$account = new Account($adminClient);
$session = $account->createEmailPasswordSession($email, $password);
// Cookie name must be a_session_<PROJECT_ID>
setcookie('a_session_[PROJECT_ID]', $session['secret'], [
'httpOnly' => true,
'secure' => true,
'sameSite' => 'strict',
'expires' => strtotime($session['expire']),
'path' => '/',
]);
$session = $_COOKIE['a_session_[PROJECT_ID]'] ?? null;
if (!$session) {
http_response_code(401);
exit;
}
$sessionClient->setSession($session);
$account = new Account($sessionClient);
$user = $account->get();
// Step 1: Redirect to OAuth provider
$account = new Account($adminClient);
$redirectUrl = $account->createOAuth2Token(
OAuthProvider::GITHUB(),
'https://example.com/oauth/success',
'https://example.com/oauth/failure',
);
header('Location: ' . $redirectUrl);
// Step 2: Handle callback — exchange token for session
$account = new Account($adminClient);
$session = $account->createSession($_GET['userId'], $_GET['secret']);
setcookie('a_session_[PROJECT_ID]', $session['secret'], [
'httpOnly' => true, 'secure' => true, 'sameSite' => 'strict',
'expires' => strtotime($session['expire']), 'path' => '/',
]);
Cookie security: Always use
httpOnly,secure, andsameSite: 'strict'to prevent XSS. The cookie name must bea_session_<PROJECT_ID>.
Forwarding user agent: Call
$sessionClient->setForwardedUserAgent($_SERVER['HTTP_USER_AGENT'])to record the end-user's browser info for debugging and security.
use Appwrite\AppwriteException;
try {
$row = $tablesDB->getRow('[DATABASE_ID]', '[TABLE_ID]', '[ROW_ID]');
} catch (AppwriteException $e) {
echo $e->getMessage(); // human-readable error message
echo $e->getCode(); // HTTP status code (int)
echo $e->getType(); // Appwrite error type string (e.g. 'document_not_found')
echo $e->getResponse(); // full response body (array)
}
Common error codes:
| Code | Meaning |
|---|---|
401 | Unauthorized — missing or invalid session/API key |
403 | Forbidden — insufficient permissions for this action |
404 | Not found — resource does not exist |
409 | Conflict — duplicate ID or unique constraint violation |
429 | Rate limited — too many requests, retry after backoff |
Appwrite uses permission strings to control access to resources. Each permission pairs an action (read, update, delete, create, or write which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the document/file level or inherited from the collection/bucket settings. Permissions are arrays of strings built with the Permission and Role helpers.
use Appwrite\Permission;
use Appwrite\Role;
$doc = $tablesDB->createRow('[DATABASE_ID]', '[TABLE_ID]', ID::unique(), [
'title' => 'Hello World'
], [
Permission::read(Role::user('[USER_ID]')), // specific user can read
Permission::update(Role::user('[USER_ID]')), // specific user can update
Permission::read(Role::team('[TEAM_ID]')), // all team members can read
Permission::read(Role::any()), // anyone (including guests) can read
]);
$file = $storage->createFile('[BUCKET_ID]', ID::unique(), InputFile::withPath('/path/to/file.png'), [
Permission::read(Role::any()),
Permission::update(Role::user('[USER_ID]')),
Permission::delete(Role::user('[USER_ID]')),
]);
When to set permissions: Set document/file-level permissions when you need per-resource access control. If all documents in a collection share the same rules, configure permissions at the collection/bucket level and leave document permissions empty.
Common mistakes:
- Forgetting permissions — the resource becomes inaccessible to all users (including the creator)
Role::any()withwrite/update/delete— allows any user, including unauthenticated guests, to modify or remove the resourcePermission::read(Role::any())on sensitive data — makes the resource publicly readable
Weekly Installs
1
Repository
First Seen
Today
Security Audits
Installed on
zencoder1
amp1
cline1
openclaw1
opencode1
cursor1
Azure 升级评估与自动化工具 - 轻松迁移 Functions 计划、托管层级和 SKU
85,700 周安装