#!/usr/bin/env bash # 云创芯 Laravel12 + Vue3(CDN) 一键安装脚本 # 适用:宝塔 Nginx + PHP 8.3 + MySQL 5.7 # 设计:零 Node、零前端构建。支持两种分发包: # - 完整包(含 vendor/):无需服务器安装 Composer,直接跑 # - 源码包(不含 vendor/):脚本自动调用 Composer 安装依赖 set -euo pipefail export COMPOSER_ALLOW_SUPERUSER=1 # 颜色(ANSI 转义,非 HEX 色值) if [ -t 1 ]; then C_OK=$'\033[0;32m'; C_WARN=$'\033[0;33m'; C_ERR=$'\033[0;31m'; C_RESET=$'\033[0m' else C_OK=''; C_WARN=''; C_ERR=''; C_RESET='' fi step() { echo; echo "${C_OK}==>${C_RESET} $*"; } ok() { echo " ${C_OK}[OK]${C_RESET} $*"; } warn() { echo " ${C_WARN}[WARN]${C_RESET} $*"; } err() { echo " ${C_ERR}[ERROR]${C_RESET} $*"; exit 1; } ROOT="$(cd "$(dirname "$0")" && pwd)" cd "$ROOT" echo "Project root: $ROOT" # ── PHP 版本检查 ──────────────────────────────────────────────── PHP_BIN="$(command -v php || true)" [ -z "$PHP_BIN" ] && err "未找到 php,请先在宝塔安装 PHP 8.3 并加入命令行。" PHP_VER="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')" PHP_MAJOR="$(php -r 'echo PHP_MAJOR_VERSION;')" PHP_MINOR="$(php -r 'echo PHP_MINOR_VERSION;')" if [ "$PHP_MAJOR" -lt 8 ] || { [ "$PHP_MAJOR" -eq 8 ] && [ "$PHP_MINOR" -lt 2 ]; }; then err "PHP $PHP_VER 过低,本项目要求 PHP >= 8.2(推荐 8.3)。" fi ok "PHP version: $PHP_VER" # ── 必要扩展检查(大小写不敏感,兼容 php -m 输出)───────────── REQ_EXT=(ctype curl dom fileinfo json mbstring openssl pdo pdo_mysql tokenizer xml) missing=() for ext in "${REQ_EXT[@]}"; do if ! php -m | grep -iqw "$ext"; then missing+=("$ext") fi done if [ ${#missing[@]} -gt 0 ]; then err "缺少 PHP 扩展: ${missing[*]}。请在宝塔 PHP-8.3 设置中安装后重试。" fi ok "All required PHP extensions present" # ── 依赖安装 ─────────────────────────────────────────────────── # 完整包已内置 vendor/,直接跳过;源码包才需要 Composer。 step "Checking PHP dependencies" if [ -f vendor/autoload.php ]; then ok "vendor/ 已内置,跳过 Composer 安装" else if ! command -v composer >/dev/null 2>&1; then warn "Composer 未安装,正在尝试自动安装..." php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php composer-setup.php --quiet rm -f composer-setup.php mv composer.phar /usr/local/bin/composer fi if ! composer --version >/dev/null 2>&1; then err "Composer 不可用。宝塔 PHP 可能禁用了 putenv/proc_open/pcntl_signal,请在【软件商店 → PHP8.3 → 设置 → 禁用函数】中删除这些函数并重启 PHP-FPM;或改用内置 vendor 的完整包。" fi ok "Composer: $(composer --version | head -n1)" composer install --no-dev --optimize-autoloader --no-interaction ok "Dependencies installed" fi # ── 运行时目录(Laravel 启动即需 bootstrap/cache 可写)────────── step "Ensuring runtime directories" mkdir -p bootstrap/cache \ storage/app/public \ storage/framework/cache/data \ storage/framework/sessions \ storage/framework/views \ storage/framework/testing \ storage/logs ok "Runtime directories ready" # ── 环境配置 ──────────────────────────────────────────────────── if [ ! -f .env ]; then step "Creating .env from .env.example" cp .env.example .env warn ".env 已从模板创建,但数据库配置仍是默认值。" warn "请先编辑 .env,填写 DB_DATABASE / DB_USERNAME / DB_PASSWORD / APP_URL," warn "保存后重新运行 ./install.sh 继续安装。" exit 0 else ok ".env already exists — 跳过覆盖(如需重置请手动删除 .env)" fi if grep -q '^DB_PASSWORD=$' .env; then err ".env 中 DB_PASSWORD 为空,请先填写数据库密码后重新运行。" fi # APP_KEY 为空才生成,避免覆盖已加密数据的密钥 if grep -q '^APP_KEY=$' .env; then php artisan key:generate --force ok "APP_KEY generated" else ok "APP_KEY already set — 保留现有密钥(覆盖会导致已加密数据无法解密)" fi # ── 存储权限 + 软链 ──────────────────────────────────────────── step "Preparing storage" chmod -R 775 storage bootstrap/cache 2>/dev/null || true # 宝塔默认运行用户为 www if id www >/dev/null 2>&1; then chown -R www:www storage bootstrap/cache 2>/dev/null || true ok "storage / bootstrap/cache 属主已设为 www" fi php artisan storage:link --force >/dev/null 2>&1 || true ok "Storage ready" # ── 数据库连通性 ─────────────────────────────────────────────── step "Testing database connection" if ! php -r ' require "vendor/autoload.php"; $app = require "bootstrap/app.php"; $app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap(); try { Illuminate\Support\Facades\DB::connection()->getPdo(); echo "OK"; } catch (Throwable $e) { fwrite(STDERR, $e->getMessage()); exit(1); } ' >/dev/null 2>&1; then err "数据库连接失败。请检查 .env 中 DB_HOST / DB_DATABASE / DB_USERNAME / DB_PASSWORD,并确认 MySQL 已启动。" fi ok "Database reachable" # ── 数据库迁移 ───────────────────────────────────────────────── step "Running migrations" php artisan migrate --force ok "Migrations done" # ── 填充种子数据(全部使用 firstOrCreate,重复执行安全)──────── step "Seeding database" php artisan db:seed --force ok "Seed data inserted (admin: admin@cloud-chip.cn / cloudchip2026)" # ── 缓存优化(生产)──────────────────────────────────────────── step "Optimizing cache" php artisan config:cache php artisan route:cache php artisan view:cache ok "Config / route / view cache built" # ── 健康检查 ─────────────────────────────────────────────────── step "Health check" APP_URL_VAL="$(grep -E '^APP_URL=' .env | head -n1 | cut -d= -f2- | tr -d '"' | tr -d "'" || true)" APP_URL_VAL="${APP_URL_VAL:-http://127.0.0.1}" if command -v curl >/dev/null 2>&1; then if curl -fsS --max-time 10 "${APP_URL_VAL%/}/api/health" >/dev/null 2>&1; then ok "API health: OK ($APP_URL_VAL)" else warn "健康检查未通过——若站点尚未在宝塔绑定域名/配置伪静态,这是正常的。" warn "完成站点配置后手动验证:curl -I ${APP_URL_VAL%/}/" fi else warn "未找到 curl,跳过健康检查。" fi echo echo "${C_OK}安装完成。${C_RESET}" echo echo "下一步:" echo " 1. 宝塔添加站点,网站目录指向本目录下的 ${C_OK}public/${C_RESET}" echo " 2. 站点设置 → 伪静态 → 选择 ${C_OK}laravel5${C_RESET}(或粘贴 DEPLOY.md 中的规则)" echo " 3. 申请 SSL 证书并开启强制 HTTPS(.env 中 SESSION_SECURE_COOKIE=true 依赖 HTTPS)" echo " 4. 访问 /admin 登录后台,先到【站点设置】核对 ICP 备案号与 SEO 信息" echo echo " 管理员账号:admin@cloud-chip.cn / cloudchip2026 ${C_WARN}(务必立即在 /settings 修改密码)${C_RESET}"