# Migração do esg de PHP 7.4 para PHP 8.3 — Relatório final

- **Data:** 2026-10-24
- **Branch:** `migracao-php83` (worktree `C:\projetos\apps\esg-php83`)
- **Base:** `main` @ `4533683` ("first commit")
- **Método:** mesma esteira do accia, aplicada no padrão dos outros apps já migrados (esg/plataforma/eletrobras/privia): composer alinhado, correções do accia portadas, lint/PHPCompatibility nos containers, comparativo 7.4 × 8.3 e fluxos de escrita.

## 1. Résumé

O esg (Yii2, mesma base CEON do accia) passa a rodar em **PHP 8.3** e continua rodando em **PHP 7.4** com o **mesmo código** (`config.platform.php = 7.4.33` no composer).

## 2. Commits

| Commit | Camada |
|---|---|
| `4e8b3ec` | `build(composer)`: dependências alinhadas ao accia para 7.4+8.3 |
| `8540fd4` | `fix(mailer)`: SwiftMailer → symfony/mailer (web e console) |
| `d50a47d` | `refactor(licenca)`: remove a integração PagSeguro inativa |
| `04035fe` | `fix`: correções PHP 8 validadas no accia (patch + rejeitos resolvidos à mão) |
| `24e8a2c` | `fix`: métodos chamados estaticamente declarados `static` |
| `9a6b1c4` | `fix(scope-token)`: comparação frouxa string × número em `?responde` |
| `c972e0e` | `fix`: `str_contains()` (função do PHP 8) trocada por `strpos() !== false` |
| `d1aa920` | `fix(performance)`: PHPlot sem `strftime()` e sem `num_points` depreciado |
| `e54e211` | `fix`: warning do PHP 8 virava erro 500 na leitura de propriedade nulo |
| `abb2af6` | `fix`: `utf8_decode`, `htmlentities` e `mb_convert_encoding` com argumentos corretos |
| `0d5c766` | `chore(assets)`: versiona `web/uploads/.gitkeep` |
| `a447add` | `docs(validacao)`: comparativo 7.4 × 8.3 e fluxos de escrita (+ harness) |

## 3. Critérios de aceite

| # | Critério | Status | Evidência |
|---|---|---|---|
| 1 | `php -l` sem erros em 8.3 e 7.4 | ✅ | containers `esg_php83` (8.3.36) e `esg_php74` (7.4.33): 0 erros |
| 2 | PHPCompatibility 7.4–8.3 | ✅ | **2 errors** (ambos informativos: `debug_backtrace()`/`func_get_args()` mudaram no PHP 7) e 8 warnings (closure sem `$this` em views) |
| 3 | `composer check-platform-reqs` / `composer validate` | ✅ | sem falha de plataforma; validate só com avisos de estilo |
| 4 | Console (`./yii`) | ✅ | sobe nos dois ambientes (Yii 2.0.55) |
| 5 | Comparativo HTTP 7.4 × 8.3 | ✅ | `03-comparacao-74x83.txt`: **47/47 URLs idênticos, 0 divergências** (mesmo código, mesmo banco `psec_vialgpd`, status + HTML normalizado) |
| 6 | Fluxos de escrita (7.4 × 8.3) | ✅ | `04-fluxos.json`: login/logout, create de `wildcard`, upload de planilha (PhpSpreadsheet), relatório Word e e-mail — mesmo efeito no banco nos dois ambientes |
| 7 | Compatibilidade dupla (7.4 com o código migrado) | ✅ | o comparativo acima já roda o **código migrado** no 7.4 |
| 8 | PagSeguro fora do código | ✅ | removido no commit `d50a47d` |
| 9 | Nenhum e-mail para fora | ✅ | `smtp.sendgrid.net` resolve para o Mailpit na rede de validação; os e-mails de teste chegaram ao Mailpit |
| 10 | Banco e container 7.4 intocados | ✅ | o banco usado foi o `psec_vialgpd` **local**, só para teste; o `php74_apache` não foi alterado |

## 4. Problems que impediam o 8.3 (corrigidos na causa)

1. **`str_contains()`** (função do PHP 8.0) em 11 views: no 7.4 é *fatal* e no 8.3 funciona — o código precisa dos dois → `strpos(...) !== false`.
2. **Leitura de propriedade de `null`** (`\Yii::$app->user->identity->name/id`, `Logged::getNameFoto()`): no 7.4 era aviso silenciado; no 8.3 é warning → o Yii transforma em `ErrorException` → **500 em qualquer página pública** (o `/template/index` quebrava assim).
3. **`strlen(null)`** em `models/BaseModel.php`: deprecation no 8.1 → **500 em todo `save()`** de modelo com coluna nula.
4. **`utf8_decode()`** (deprecado no 8.2) → `mb_convert_encoding`.
5. **`htmlentities()`**: o default de flags mudou no 8.1 → flags explícitos.
6. **PHPlot**: `strftime()` deprecado no 8.1 → helper que traduz o formato para `date()`; `ImagePolygon()/ImageFilledPolygon()`: `num_points` é obrigatório no 7.4 e deprecado no 8.1 → helper que monta os argumentos conforme a versão (sem suprimir deprecation).
7. **`mb_convert_encoding($rotulo, "UTF-8")`** com 2 argumentos: *fatal* em qualquer PHP ≥ 7.1 (defeito antigo, não da migração).
8. **`actionWordOld`**: leituras de `$coleta` nulo → 500 no 8.3.
9. **Métodos de instância chamados estaticamente** (`BpItem::somaMes`, `BpSubtipo::calculaExpressao`) → `static`.

## 5. Como reproduzir

```powershell
docker run -d --name esg_php83 --network php83_php83_val -p 8097:80 `
  -v C:\projetos\apps:/var/www/html -v C:\projetos\php83\vhosts-esg:/etc/apache2/sites-enabled `
  -v C:\projetos\php83\mailpit\cert.pem:/usr/local/share/ca-certificates/mailpit.crt:ro `
  --env-file C:\projetos\apps\esg-php83\.env -e APP_DATABASE_HOST=mysql57 `
  -e APP_DATABASE_DB=psec_vialgpd php83-apache sh -c "mkdir -p /var/log/php && update-ca-certificates && exec apache2-foreground"

# mesma coisa com a imagem projetos-webserver (7.4) e a porta 8098
docker exec esg_php83 sh /tmp/lint.sh /var/www/html/esg-php83
python tools\migracao-php83\compara_urls.py
python tools\migracao-php83\fluxos.py
```

O `.env` do app é local (ignorado pelo git) e aponta para o `psec_vialgpd` local, usado só para teste.

## 6. Não verificado

- **PDF (mpdf)** e **QR (qrcode-library 3.x)**: sem dados no banco de teste para gerar o protocolo; o QR sai em SVG e não foi decodificado.
- **`yii2mod/yii2-swagger`** (documentação da API): não exercitada.
- **Integrações externas** — SendGrid (transporte preservado) não foi exercitado contra o servidor real.
- **`moonlandsoft/yii2-phpexcel`** (export/import de Excel): o pacote resolve para a versão baseada em PhpSpreadsheet; o fluxo não foi exercitado.

## 7. Pendências

1. Publicar a branch (`git push -u origin migracao-php83`).
2. Merge e deploy; `composer install --no-dev` no servidor e `php.ini` de produção (`E_ALL & ~E_DEPRECATED & ~E_STRICT`).
3. Verificar no servidor de produção as telas públicas (o bug do `identity->name` derrubava qualquer página sem usuário logado) e os gráficos do PHPlot.
4. Remover os containers de teste `esg_php83` / `esg_php74` e o vhost `C:\projetos\php83\vhosts-esg` quando não forem mais usados.
