AI-powered adeno-associated virus (AAV) vector design for gene therapy including capsid engineering, promoter selection, and tropism optimization.
中文简介正在准备中。当前显示原文说明。
PHP 8.0+ development — XAMPP, RESTful APIs, PDO/MySQL/MariaDB, and authentication. Use when building PHP backends, creating API endpoints, configuring XAMPP, or integrating PHP with databases.
中文简介正在准备中。当前显示原文说明。
安装前可以查看交给 AI 代理的指令内容。
Optimized for current PHP 8.x releases, PHPUnit 11+, Composer 2.x, and PDO-backed MySQL or MariaDB apps.
Expert guidance for building high-quality PHP applications with PHP 8.0+, PDO for secure database access, RESTful API design, and XAMPP environment configuration following official PHP documentation at https://php.net.
Before claiming "skill applied successfully":
<?php
// Before
$stmt = $pdo->query("SELECT * FROM users WHERE email = '$email'");
$user = $stmt->fetch();
// After
$stmt = $pdo->prepare('SELECT id, email, password_hash FROM users WHERE email = :email LIMIT 1');
$stmt->execute(['email' => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
Replaces string interpolation with a prepared statement and a narrower result shape.
Use symptom -> action triggers: when one matches, apply this skill and verify with the protocol below.
Core PHP Development:
Database & Data Layer:
Security & Best Practices:
API Development:
<?php
// Named arguments (PHP 8.0+)
function createUser(string $name, string $email, bool $isAdmin = false): User {
return new User($name, $email, $isAdmin);
}
// Call with named arguments
$user = createUser(email: 'user@example.com', name: 'John Doe');
// Union types (PHP 8.0+)
function processValue(string|int|float $value): string {
return (string)$value;
}
// Nullsafe operator (PHP 8.0+)
$country = $session?->user?->address?->country ?? 'Unknown';
// Constructor property promotion (PHP 8.0+)
class User {
public function __construct(
public string $name,
public string $email,
private string $passwordHash
) {}
}
<?php
declare(strict_types=1); // Enforce type safety
// Typed properties and return types
class Recipe {
private int $id;
private string $title;
private ?DateTime $createdAt;
public function __construct(int $id, string $title) {
$this->id = $id;
$this->title = $title;
}
public function getTitle(): string {
return $this->title;
}
public function setCreatedAt(?DateTime $date): void {
$this->createdAt = $date;
}
}
// Union and intersection types
function processData(string|array $data): string|int {
return is_array($data) ? count($data) : strlen($data);
}
<?php
class Database {
private static ?PDO $instance = null;
public static function getInstance(): PDO {
if (self::$instance === null) {
$host = $_ENV['DB_HOST'] ?? 'localhost';
$dbname = $_ENV['DB_NAME'] ?? 'recipe_sharing_system';
$username = $_ENV['DB_USER'] ?? 'root';
$password = $_ENV['DB_PASSWORD'] ?? '';
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$dbname;charset=$charset";
try {
self::$instance = new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
]);
} catch (PDOException $e) {
error_log("Database connection failed: " . $e->getMessage());
throw new RuntimeException("Database connection error");
}
}
return self::$instance;
}
}
<?php
class UserRepository {
private PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
}
// Find user by email with prepared statement
public function findByEmail(string $email): ?array {
$stmt = $this->db->prepare(
"SELECT id, email, password_hash, role, status
FROM user
WHERE email = :email LIMIT 1"
);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->execute();
$user = $stmt->fetch();
return $user ?: null;
}
// Create new user with password hashing
public function create(string $name, string $email, string $password): int {
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $this->db->prepare(
"INSERT INTO user (name, email, password_hash, role, status, created_at, updated_at)
VALUES (:name, :email, :password_hash, 'user', 'active', NOW(), NOW())"
);
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
$stmt->bindParam(':password_hash', $passwordHash, PDO::PARAM_STR);
$stmt->execute();
return (int) $this->db->lastInsertId();
}
// Authentication with password verification
public function authenticate(string $email, string $password): ?array {
$user = $this->findByEmail($email);
if ($user === null) {
return null;
}
if (!password_verify($password, $user['password_hash'])) {
return null;
}
// Check if password needs rehash
if (password_needs_rehash($user['password_hash'], PASSWORD_DEFAULT)) {
$newHash = password_hash($password, PASSWORD_DEFAULT);
$this->updatePasswordHash($user['id'], $newHash);
}
unset($user['password_hash']); // Remove sensitive data
return $user;
}
private function updatePasswordHash(int $userId, string $hash): void {
$stmt = $this->db->prepare(
"UPDATE user SET password_hash = :hash WHERE id = :id"
);
$stmt->execute([':hash' => $hash, ':id' => $userId]);
}
}
<?php
class RecipeService {
private PDO $db;
public function __construct(PDO $db) {
$this->db = $db;
}
// Create recipe with ingredients, instructions, and images in a transaction
public function createRecipeWithDetails(array $recipeData, array $ingredients, array $instructions): int {
try {
$this->db->beginTransaction();
// Insert recipe
$stmt = $this->db->prepare(
"INSERT INTO recipe (title, description, category, difficulty, prep_time, cook_time, servings, author_id, status, created_at, updated_at)
VALUES (:title, :description, :category, :difficulty, :prep_time, :cook_time, :servings, :author_id, 'pending', NOW(), NOW())"
);
$stmt->execute([
':title' => $recipeData['title'],
':description' => $recipeData['description'],
':category' => $recipeData['category'],
':difficulty' => $recipeData['difficulty'],
':prep_time' => $recipeData['prepTime'],
':cook_time' => $recipeData['cookTime'],
':servings' => $recipeData['servings'],
':author_id' => $recipeData['authorId'],
]);
$recipeId = (int) $this->db->lastInsertId();
// Insert ingredients
$ingredientStmt = $this->db->prepare(
"INSERT INTO ingredient (recipe_id, name, quantity, unit, sort_order, created_at, updated_at)
VALUES (:recipe_id, :name, :quantity, :unit, :sort_order, NOW(), NOW())"
);
foreach ($ingredients as $index => $ingredient) {
$ingredientStmt->execute([
':recipe_id' => $recipeId,
':name' => $ingredient['name'],
':quantity' => $ingredient['quantity'],
':unit' => $ingredient['unit'],
':sort_order' => $index,
]);
}
// Insert instructions
$instructionStmt = $this->db->prepare(
"INSERT INTO instruction (recipe_id, step_number, instruction_text, created_at, updated_at)
VALUES (:recipe_id, :step_number, :instruction_text, NOW(), NOW())"
);
foreach ($instructions as $index => $instruction) {
$instructionStmt->execute([
':recipe_id' => $recipeId,
':step_number' => $index + 1,
':instruction_text' => $instruction['text'],
]);
}
$this->db->commit();
return $recipeId;
} catch (Exception $e) {
$this->db->rollBack();
error_log("Failed to create recipe: " . $e->getMessage());
throw $e;
}
}
}
<?php
class Response {
public static function json(mixed $data, int $statusCode = 200): never {
http_response_code($statusCode);
header('Content-Type: application/json; charset=utf-8');
echo json_encode($data, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
exit;
}
public static function error(string $message, int $statusCode = 400): never {
self::json([
'success' => false,
'error' => $message,
], $statusCode);
}
public static function success(mixed $data = null, string $message = 'Success'): never {
self::json([
'success' => true,
'message' => $message,
'data' => $data,
]);
}
}
<?php
// Handle CORS headers
$allowedOrigins = [
'http://localhost:5173', // Vite dev server
'http://localhost:3000', // Alternative dev server
];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins, true)) {
header("Access-Control-Allow-Origin: $origin");
}
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Credentials: true');
// Handle preflight requests
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
<?php
function requireAuth(): array {
$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (!preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
Response::error('Unauthorized: Missing or invalid token', 401);
}
$token = $matches[1];
// Validate token (example withJWT)
try {
$payload = JWT::decode($token, $_ENV['JWT_SECRET'], ['HS256']);
return (array) $payload;
} catch (Exception $e) {
Response::error('Unauthorized: Invalid token', 401);
}
}
function requireAdmin(): array {
$user = requireAuth();
if ($user['role'] !== 'admin') {
Response::error('Forbidden: Admin access required', 403);
}
return $user;
}
<?php
require_once '../../config/database.php';
require_once '../../middleware/cors.php';
require_once '../../utils/response.php';
class RecipeController {
private PDO $db;
public function __construct() {
$this->db = Database::getInstance();
}
// GET /api/recipes - Get all published recipes
public function index(): void {
$category = $_GET['category'] ?? null;
$difficulty = $_GET['difficulty'] ?? null;
$search = $_GET['search'] ?? null;
$limit = (int)($_GET['limit'] ?? 20);
$offset = (int)($_GET['offset'] ?? 0);
$query = "SELECT r.*, u.name as author_name,
COUNT(DISTINCT rv.id) as view_count,
COUNT(DISTINCT lr.id) as like_count,
AVG(rev.rating) as average_rating
FROM recipe r
JOIN user u ON r.author_id = u.id
LEFT JOIN recipe_view rv ON r.id = rv.recipe_id
LEFT JOIN like_record lr ON r.id = lr.recipe_id
LEFT JOIN review rev ON r.id = rev.recipe_id
WHERE r.status = 'published'";
$params = [];
if ($category !== null) {
$query .= " AND r.category = :category";
$params[':category'] = $category;
}
if ($difficulty !== null) {
$query .= " AND r.difficulty = :difficulty";
$params[':difficulty'] = $difficulty;
}
if ($search !== null) {
$query .= " AND (r.title LIKE :search OR r.description LIKE :search)";
$searchTerm = "%$search%";
$params[':search'] = $searchTerm;
$params[':search2'] = $searchTerm;
}
$query .= " GROUP BY r.id ORDER BY r.created_at DESC LIMIT :limit OFFSET :offset";
$stmt = $this->db->prepare($query);
$stmt->execute($params);
$recipes = $stmt->fetchAll();
Response::success($recipes);
}
// GET /api/recipes/:id - Get recipe by ID
public function show(int $id): void {
$stmt = $this->db->prepare(
"SELECT r.*, u.name as author_name, u.email as author_email,
GROUP_CONCAT(CONCAT(i.name, ' (', i.quantity, ' ', i.unit, ')') SEPARATOR ', ') as ingredients
FROM recipe r
JOIN user u ON r.author_id = u.id
LEFT JOIN ingredient i ON r.id = i.recipe_id
WHERE r.id = :id
GROUP BY r.id"
);
$stmt->execute([':id' => $id]);
$recipe = $stmt->fetch();
if ($recipe === false) {
Response::error('Recipe not found', 404);
}
// Fetch instructions
$instStmt = $this->db->prepare(
"SELECT step_number, instruction_text
FROM instruction
WHERE recipe_id = :recipe_id
ORDER BY step_number"
);
$instStmt->execute([':recipe_id' => $id]);
$recipe['instructions'] = $instStmt->fetchAll();
Response::success($recipe);
}
// POST /api/recipes - Create new recipe
public function store(): void {
$user = requireAuth();
$data = json_decode(file_get_contents('php://input'), true);
// Validate required fields
if (empty($data['title']) || empty($data['description'])) {
Response::error('Title and description are required');
}
$recipeData = [
'title' => $data['title'],
'description' => $data['description'],
'category' => $data['category'] ?? 'Uncategorized',
'difficulty' => $data['difficulty'] ?? 'Medium',
'prepTime' => (int)($data['prepTime'] ?? 0),
'cookTime' => (int)($data['cookTime'] ?? 0),
'servings' => (int)($data['servings'] ?? 1),
'authorId' => $user['id'],
];
$recipeService = new RecipeService($this->db);
try {
$recipeId = $recipeService->createRecipeWithDetails(
$recipeData,
$data['ingredients'] ?? [],
$data['instructions'] ?? []
);
Response::success(['id' => $recipeId], 'Recipe created successfully', 201);
} catch (Exception $e) {
Response::error('Failed to create recipe: ' . $e->getMessage(), 500);
}
}
}
<?php
class Validator {
public static function email(string $email): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
public static function string(string $value, int $min = 1, int $max = 255): bool {
$length = strlen($value);
return $length >= $min && $length <= $max;
}
public static function integer(int $value, int $min = PHP_INT_MIN, int $max = PHP_INT_MAX): bool {
return $value >= $min && $value <= $max;
}
public static function enum(string $value, array $allowed): bool {
return in_array($value, $allowed, true);
}
public static function required(array $data, array $fields): array {
$errors = [];
foreach ($fields as $field) {
if (empty($data[$field])) {
$errors[] = "$field is required";
}
}
return $errors;
}
public static function sanitize(string $input): string {
return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
}
}
<?php
function validateRecipeData(array $data): array {
$errors = [];
// Validate title
if (empty($data['title'])) {
$errors[] = 'Title is required';
} elseif (!Validator::string($data['title'], 3, 200)) {
$errors[] = 'Title must be between 3 and 200 characters';
}
// Validate email
if (!empty($data['email']) && !Validator::email($data['email'])) {
$errors[] = 'Invalid email address';
}
// Validate rating
if (isset($data['rating']) && !Validator::integer((int)$data['rating'], 1, 5)) {
$errors[] = 'Rating must be between 1 and 5';
}
// Validate difficulty
if (!empty($data['difficulty']) &&
!Validator::enum($data['difficulty'], ['Easy', 'Medium', 'Hard'])) {
$errors[] = 'Difficulty must be Easy, Medium, or Hard';
}
// Sanitize all string inputs
foreach ($data as $key => $value) {
if (is_string($value)) {
$data[$key] = Validator::sanitize($value);
}
}
return ['errors' => $errors, 'data' => $data];
}
<?php
class PasswordManager {
public static function hash(string $password): string {
// Use algorithm recommended by PHP
return password_hash($password, PASSWORD_DEFAULT);
}
public static function verify(string $password, string $hash): bool {
return password_verify($password, $hash);
}
public static function needsRehash(string $hash): bool {
return password_needs_rehash($hash, PASSWORD_DEFAULT);
}
public static function validateStrength(string $password): array {
$errors = [];
if (strlen($password) < 8) {
$errors[] = 'Password must be at least 8 characters';
}
if (!preg_match('/[A-Z]/', $password)) {
$errors[] = 'Password must contain at least one uppercase letter';
}
if (!preg_match('/[a-z]/', $password)) {
$errors[] = 'Password must contain at least one lowercase letter';
}
if (!preg_match('/[0-9]/', $password)) {
$errors[] = 'Password must contain at least one number';
}
if (!preg_match('/[!@#$%^&*(),.?":{}|<>]/', $password)) {
$errors[] = 'Password must contain at least one special character';
}
return $errors;
}
}
<?php
class Session {
public static function start(): void {
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
}
public static function set(string $key, mixed $value): void {
$_SESSION[$key] = $value;
}
public static function get(string $key, mixed $default = null): mixed {
return $_SESSION[$key] ?? $default;
}
public static function remove(string $key): void {
unset($_SESSION[$key]);
}
public static function destroy(): void {
$_SESSION = [];
session_destroy();
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
}
public static function regenerateId(): void {
session_regenerate_id(true);
}
}
<?php
class CsrfProtection {
public static function generateToken(): string {
if (!isset($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
return $_SESSION['csrf_token'];
}
public static function validateToken(string $token): bool {
return isset($_SESSION['csrf_token']) &&
hash_equals($_SESSION['csrf_token'], $token);
}
public static function invalidateToken(): void {
unset($_SESSION['csrf_token']);
}
public static function getInputField(): string {
$token = self::generateToken();
return "<input type='hidden' name='csrf_token' value='$token'>";
}
}
.htaccess for URL RewritingRewriteEngine On
# Redirect trailing slashes
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Handle API routes
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^api/(.*)$ api/index.php [QSA,L]
# Handle frontend routes (SPA)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.html [QSA,L]
; Enable error reporting for development
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
; Log errors in production
log_errors = On
error_log = "C:/xampp/php/logs/php_error.log"
; Increase upload limits
upload_max_filesize = 10M
post_max_size = 10M
; Enable PDO extensions
extension=pdo_mysql
extension=mysqli
; Enable session handling
session.save_handler = files
session.save_path = "C:/xampp/tmp"
session.use_strict_mode = 1
session.cookie_httponly = 1
session.cookie_secure = 0 ; Set to 1 if HTTPS
session.use_only_cookies = 1
; Set timezone
date.timezone = "Asia/Bangkok"
declare(strict_types=1))password_hash()This skill is written to stay usable across GitHub Copilot, Claude Code, and Codex.
$CODEX_HOME/skills/php-development and restart Codex after major changes.Preferred MCP Server: None required
SKILL.md, bundled references or scripts, and manual verification. Show the exact commands, evidence, and final checks you used before concluding."还没有评价。欢迎分享你的使用感受。
无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。
还没有评论。来写第一条吧。
AI-powered adeno-associated virus (AAV) vector design for gene therapy including capsid engineering, promoter selection, and tropism optimization.
中文简介正在准备中。当前显示原文说明。
Improve the clarity and voice of AI-assisted academic writing (papers, theses, rebuttals) and
中文简介正在准备中。当前显示原文说明。
12-agent academic paper writing pipeline. 11 modes (full/plan/outline/revision/revision-coach/abstract/lit-review/format-convert/citation-check/disclosure/rebuttal-audit). 6 paper types, 5 citation formats, bilingual abstracts, LaTeX/DOCX-via-Pandoc/PDF output. Style Calibration + Writing Quality Check + Anti-Patterns with IRON RULE markers. Triggers: write paper, academic paper, guide my paper, parse reviews, audit my rebuttal, check my response draft, AI disclosure, 寫論文, 學術論文, 引導我寫論文, 審查意見, 評估回覆, 논문 작성, 초록 작성, 논문 수정, 논문 계획을 도와줘, 심사 의견 반영, 답변서 점검, AI 사용 고지.
中文简介正在准备中。当前显示原文说明。
Systematic writing framework for philosophy and interdisciplinary academic papers from optimized outline to submission-ready manuscript. Use when users want to: (1) write a paper from a detailed outline, (2) ensure quality control during writing, (3) maintain consistency across chapters, (4) prepare a submission-ready manuscript, or (5) systematically execute a planned paper. Triggered by phrases like 'write the paper from this outline,' 'compose the full manuscript,' 'execute the outline,' or when users have completed strategic planning (academic-paper-strategist skill) and are ready to write. Takes optimized outline as input; outputs complete manuscript with iterative quality checks.
中文简介正在准备中。当前显示原文说明。
Multi-perspective academic paper review with dynamic reviewer personas. Runs a 5-seat, role-separated review panel (Journal-Fit Reviewer + 3 peer-review roles + Devil's Advocate) with field-specific expertise; role separation is not a claim of independent error processes. Supports full review, re-review (verification), quick assessment, methodology focus, Socratic guided, and calibration modes. Triggers on: review paper, peer review, manuscript review, referee report, review my paper, critique paper, simulate review, editorial review, calibrate reviewer, reviewer calibration, measure reviewer accuracy, 審查論文, 論文審查, 模擬審查, 同儕審查, 幫我審這篇, 以審查人角度評估, 審查者校準, 논문 심사, 동료 심사, 모의 심사, 심사자 관점에서 평가, 심사자 보정.
中文简介正在准备中。当前显示原文说明。
Systematic strategic planning framework for philosophy and interdisciplinary academic papers targeting preprint platforms (PhilArchive, arXiv, PhilSci-Archive). Use when users want to: (1) plan a paper on a specific topic, (2) identify research gaps and assess originality, (3) develop optimized paper outlines, (4) prepare for preprint submission, or (5) understand platform requirements and writing standards. Triggered by phrases like 'plan a paper on,' 'help me design a paper about,' 'identify research gaps in,' 'is this idea original,' or when users need structured research planning. The skill guides through three phases: Platform Analysis (identifying target venue and studying sample papers), Theoretical Framework (AI-driven literature search and gap identification), and Outline Optimization (structured design with reviewer-perspective self-assessment). Each phase includes quality evaluation standards and validation checkpoints.
中文简介正在准备中。当前显示原文说明。