# Tài liệu API Locket - Hướng dẫn tích hợp PHP

## Tổng quan
API của Locket sử dụng Firebase Authentication và Firebase Storage để xác thực và lưu trữ media. Dưới đây là các endpoints và phương thức cần thiết để tích hợp.

---

## 1. ĐĂNG NHẬP (Login)

### Endpoint
```
POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyCQngaaXQIfJaH0aS2l7REgIjD7nL431So
```

### Headers
```php
$headers = [
    "Accept: */*",
    "Accept-Encoding: gzip, deflate, br",
    "Accept-Language: en",
    "baggage: sentry-environment=production,sentry-public_key=78fa64317f434fd89d9cc728dd168f50,sentry-release=com.locket.Locket@1.82.0+3,sentry-trace_id=90310ccc8ddd4d059b83321054b6245b",
    "Connection: keep-alive",
    "Content-Type: application/json",
    "Host: www.googleapis.com",
    "sentry-trace: 90310ccc8ddd4d059b83321054b6245b-3a4920b34e94401d-0",
    "User-Agent: FirebaseAuth.iOS/10.23.1 com.locket.Locket/1.82.0 iPhone/18.0 hw/iPhone12_1",
    "X-Client-Version: iOS/FirebaseSDK/10.23.1/FirebaseCore-iOS",
    "X-Firebase-AppCheck: eyJraWQiOiJNbjVDS1EiLCJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxOjY0MTAyOTA3NjA4Mzppb3M6Y2M4ZWI0NjI5MGQ2OWIyMzRmYTYwNiIsImF1ZCI6WyJwcm9qZWN0c1wvNjQxMDI5MDc2MDgzIiwicHJvamVjdHNcL2xvY2tldC00MjUyYSJdLCJwcm92aWRlciI6ImRldmljZV9jaGVja19kZXZpY2VfaWRlbnRpZmljYXRpb24iLCJpc3MiOiJodHRwczpcL1wvZmlyZWJhc2VhcHBjaGVjay5nb29nbGVhcGlzLmNvbVwvNjQxMDI5MDc2MDgzIiwiZXhwIjoxNzIyMTY3ODk4LCJpYXQiOjE3MjIxNjQyOTgsImp0aSI6ImlHUGlsT1dDZGg4Mll3UTJXRC1neEpXeWY5TU9RRFhHcU5OR3AzTjFmRGcifQ.lqTOJfdoYLpZwYeeXtRliCdkVT7HMd7_Lj-d44BNTGuxSYPIa9yVAR4upu3vbZSh9mVHYS8kJGYtMqjP-L6YXsk_qsV_gzKC2IhVAV6KbPDRHdevMfBC6fRiOSVn7vt749GVFdZqAuDCXhCILsaMhvgDBgZoDilgAPtpNwyjz-VtRB7OdOUbuKTCqdoSOX0SJWVUMyuI8nH0-unY--YRctunK8JHZDxBaM_ahVggYPWBCpzxq9Yeq8VSPhadG_tGNaADStYPaeeUkZ7DajwWqH5ze6ESpuFNgAigwPxCM735_ZiPeD7zHYwppQA9uqTWszK9v9OvWtFCsgCEe22O8awbNbuEBTKJpDQ8xvZe8iEYyhfUPncER3S-b1CmuXR7tFCdTgQe5j7NGWjFvN_CnL7D2nudLwxWlpqwASCHvHyi8HBaJ5GpgriTLXAAinY48RukRDBi9HwEzpRecELX05KTD2lTOfQCjKyGpfG2VUHP5Xm36YbA3iqTDoDXWMvV",
    "X-Firebase-GMPID: 1:641029076083:ios:cc8eb46290d69b234fa606",
    "X-Ios-Bundle-Identifier: com.locket.Locket"
];
```

### Request Body
```php
$data = [
    "email" => "email@example.com",
    "password" => "password123",
    "clientType" => "CLIENT_TYPE_IOS",
    "returnSecureToken" => true
];
```

### Response
```json
{
    "localId": "user_id_here",
    "email": "email@example.com",
    "displayName": "User Name",
    "idToken": "firebase_id_token_here",
    "profilePicture": "url_to_profile_picture"
}
```

### Ví dụ PHP Code
```php
function locketLogin($email, $password) {
    $url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyCQngaaXQIfJaH0aS2l7REgIjD7nL431So";
    
    $data = json_encode([
        "email" => $email,
        "password" => $password,
        "clientType" => "CLIENT_TYPE_IOS",
        "returnSecureToken" => true
    ]);
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        "Content-Type: application/json",
        "User-Agent: FirebaseAuth.iOS/10.23.1 com.locket.Locket/1.82.0 iPhone/18.0 hw/iPhone12_1",
        "X-Client-Version: iOS/FirebaseSDK/10.23.1/FirebaseCore-iOS",
        "X-Firebase-GMPID: 1:641029076083:ios:cc8eb46290d69b234fa606"
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($response, true);
}

// Sử dụng
$result = locketLogin("your_email@example.com", "your_password");
$userId = $result['localId'];
$idToken = $result['idToken'];
```

---

## 2. UPLOAD ẢNH (Upload Image)

### Bước 1: Khởi tạo Resumable Upload

**Endpoint:**
```
POST https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{userId}%2Fmoments%2Fthumbnails%2F{imageName}?uploadType=resumable&name=users%2F{userId}%2Fmoments%2Fthumbnails%2F{imageName}
```

**Headers:**
```php
$headers = [
    'content-type: application/json; charset=UTF-8',
    'authorization: Bearer ' . $idToken,
    'x-goog-upload-protocol: resumable',
    'accept: */*',
    'x-goog-upload-command: start',
    'x-goog-upload-content-length: ' . $imageSize,
    'accept-language: vi-VN,vi;q=0.9',
    'x-firebase-storage-version: ios/10.13.0',
    'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)',
    'x-goog-upload-content-type: image/webp',
    'x-firebase-gmpid: 1:641029076083:ios:cc8eb46290d69b234fa609'
];
```

**Request Body:**
```json
{
    "name": "users/{userId}/moments/thumbnails/{imageName}",
    "contentType": "image/*",
    "bucket": "",
    "metadata": {
        "creator": "{userId}",
        "visibility": "private"
    }
}
```

**Response Header:**
- Lấy giá trị của header `X-Goog-Upload-URL` để dùng cho bước 2

### Bước 2: Upload File thực tế

**Endpoint:**
```
PUT {uploadUrl từ bước 1}
```

**Headers:**
```php
$headers = [
    'content-type: application/octet-stream',
    'x-goog-upload-protocol: resumable',
    'x-goog-upload-offset: 0',
    'x-goog-upload-command: upload, finalize',
    'upload-incomplete: ?0',
    'upload-draft-interop-version: 3',
    'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)'
];
```

**Body:** Binary image data

### Bước 3: Lấy Download URL

**Endpoint:**
```
GET https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{userId}%2Fmoments%2Fthumbnails%2F{imageName}
```

**Headers:**
```php
$headers = [
    'content-type: application/json; charset=UTF-8',
    'authorization: Bearer ' . $idToken
];
```

**Response:**
```json
{
    "downloadTokens": "token_here"
}
```

**Final URL:**
```
https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{userId}%2Fmoments%2Fthumbnails%2F{imageName}?alt=media&token={downloadToken}
```

### Ví dụ PHP Code - Upload Image
```php
function uploadImageToLocket($userId, $idToken, $imageData) {
    $imageName = time() . "_image.webp";
    $imageSize = strlen($imageData);
    
    // Bước 1: Khởi tạo upload
    $url = "https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{$userId}%2Fmoments%2Fthumbnails%2F{$imageName}?uploadType=resumable&name=users%2F{$userId}%2Fmoments%2Fthumbnails%2F{$imageName}";
    
    $metadata = json_encode([
        "name" => "users/{$userId}/moments/thumbnails/{$imageName}",
        "contentType" => "image/*",
        "bucket" => "",
        "metadata" => [
            "creator" => $userId,
            "visibility" => "private"
        ]
    ]);
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $metadata);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/json; charset=UTF-8',
        'authorization: Bearer ' . $idToken,
        'x-goog-upload-protocol: resumable',
        'x-goog-upload-command: start',
        'x-goog-upload-content-length: ' . $imageSize,
        'x-firebase-storage-version: ios/10.13.0',
        'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)',
        'x-goog-upload-content-type: image/webp',
        'x-firebase-gmpid: 1:641029076083:ios:cc8eb46290d69b234fa609'
    ]);
    
    $response = curl_exec($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $headers = substr($response, 0, $headerSize);
    curl_close($ch);
    
    // Lấy Upload URL
    preg_match('/X-Goog-Upload-URL: (.*)/', $headers, $matches);
    $uploadUrl = trim($matches[1]);
    
    // Bước 2: Upload file
    $ch = curl_init($uploadUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/octet-stream',
        'x-goog-upload-protocol: resumable',
        'x-goog-upload-offset: 0',
        'x-goog-upload-command: upload, finalize',
        'upload-incomplete: ?0',
        'upload-draft-interop-version: 3',
        'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)'
    ]);
    
    curl_exec($ch);
    curl_close($ch);
    
    // Bước 3: Lấy download URL
    $getUrl = "https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{$userId}%2Fmoments%2Fthumbnails%2F{$imageName}";
    
    $ch = curl_init($getUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/json; charset=UTF-8',
        'authorization: Bearer ' . $idToken
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    $downloadToken = $data['downloadTokens'];
    
    return "{$getUrl}?alt=media&token={$downloadToken}";
}
```

---

## 3. UPLOAD VIDEO (Upload Video)

### Quy trình tương tự Upload Image nhưng có sự khác biệt:

**Firebase Storage Bucket:** `locket-video` (thay vì `locket-img`)
**Path:** `users/{userId}/moments/videos/{videoName}`
**Content-Type:** `video/mp4`
**File Extension:** `.mp4`

### Ví dụ PHP Code - Upload Video
```php
function uploadVideoToLocket($userId, $idToken, $videoData) {
    $videoName = time() . "_video.mp4";
    $videoSize = strlen($videoData);
    
    // Bước 1: Khởi tạo upload
    $url = "https://firebasestorage.googleapis.com/v0/b/locket-video/o/users%2F{$userId}%2Fmoments%2Fvideos%2F{$videoName}?uploadType=resumable&name=users%2F{$userId}%2Fmoments%2Fvideos%2F{$videoName}";
    
    $metadata = json_encode([
        "name" => "users/{$userId}/moments/videos/{$videoName}",
        "contentType" => "video/mp4",
        "bucket" => "",
        "metadata" => [
            "creator" => $userId,
            "visibility" => "private"
        ]
    ]);
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $metadata);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/json; charset=UTF-8',
        'authorization: Bearer ' . $idToken,
        'x-goog-upload-protocol: resumable',
        'x-goog-upload-command: start',
        'x-goog-upload-content-length: ' . $videoSize,
        'x-firebase-storage-version: ios/10.13.0',
        'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)',
        'x-goog-upload-content-type: video/mp4',
        'x-firebase-gmpid: 1:641029076083:ios:cc8eb46290d69b234fa609'
    ]);
    
    $response = curl_exec($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $headers = substr($response, 0, $headerSize);
    curl_close($ch);
    
    // Lấy Upload URL
    preg_match('/X-Goog-Upload-URL: (.*)/', $headers, $matches);
    $uploadUrl = trim($matches[1]);
    
    // Bước 2: Upload file
    $ch = curl_init($uploadUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_setopt($ch, CURLOPT_POSTFIELDS, $videoData);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/octet-stream',
        'x-goog-upload-protocol: resumable',
        'x-goog-upload-offset: 0',
        'x-goog-upload-command: upload, finalize',
        'upload-incomplete: ?0',
        'upload-draft-interop-version: 3',
        'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)'
    ]);
    
    curl_exec($ch);
    curl_close($ch);
    
    // Bước 3: Lấy download URL
    $getUrl = "https://firebasestorage.googleapis.com/v0/b/locket-video/o/users%2F{$userId}%2Fmoments%2Fvideos%2F{$videoName}";
    
    $ch = curl_init($getUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/json; charset=UTF-8',
        'authorization: Bearer ' . $idToken
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    $data = json_decode($response, true);
    $downloadToken = $data['downloadTokens'];
    
    return "{$getUrl}?alt=media&token={$downloadToken}";
}
```

---

## 4. POST IMAGE/VIDEO LÊN LOCKET (Post Moment)

### Endpoint
```
POST https://api.locketcamera.com/postMomentV2
```

### Post Image

**Headers:**
```php
$headers = [
    'content-type: application/json',
    'authorization: Bearer ' . $idToken
];
```

**Request Body:**
```json
{
    "data": {
        "thumbnail_url": "url_from_firebase_storage",
        "caption": "Your caption here",
        "sent_to_all": true
    }
}
```

### Post Video

**Request Body (phức tạp hơn):**
```json
{
    "data": {
        "thumbnail_url": "thumbnail_url_here",
        "video_url": "video_url_here",
        "md5": "video_url_hashcode",
        "recipients": [],
        "analytics": {
            "experiments": {
                "flag_4": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "43"},
                "flag_10": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "505"},
                "flag_23": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "400"},
                "flag_22": {"value": "1203", "@type": "type.googleapis.com/google.protobuf.Int64Value"},
                "flag_19": {"value": "52", "@type": "type.googleapis.com/google.protobuf.Int64Value"},
                "flag_18": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "1203"},
                "flag_16": {"value": "303", "@type": "type.googleapis.com/google.protobuf.Int64Value"},
                "flag_15": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "501"},
                "flag_14": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "500"},
                "flag_25": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "23"}
            },
            "amplitude": {
                "device_id": "BF5D1FD7-9E4D-4F8B-AB68-B89ED20398A6",
                "session_id": {"value": "1722437166613", "@type": "type.googleapis.com/google.protobuf.Int64Value"}
            },
            "google_analytics": {"app_instance_id": "5BDC04DA16FF4B0C9CA14FFB9C502900"},
            "platform": "ios"
        },
        "sent_to_all": true,
        "caption": "Your caption",
        "overlays": [
            {
                "data": {
                    "text": "Your caption",
                    "text_color": "#FFFFFFE6",
                    "type": "standard",
                    "max_lines": {"@type": "type.googleapis.com/google.protobuf.Int64Value", "value": "4"},
                    "background": {"material_blur": "ultra_thin", "colors": []}
                },
                "alt_text": "Your caption",
                "overlay_id": "caption:standard",
                "overlay_type": "caption"
            }
        ]
    }
}
```

### Ví dụ PHP Code - Post Image
```php
function postImageToLocket($idToken, $thumbnailUrl, $caption) {
    $url = "https://api.locketcamera.com/postMomentV2";
    
    $data = json_encode([
        "data" => [
            "thumbnail_url" => $thumbnailUrl,
            "caption" => $caption,
            "sent_to_all" => true
        ]
    ]);
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/json',
        'authorization: Bearer ' . $idToken
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    return $httpCode == 200;
}
```

### Ví dụ PHP Code - Post Video
```php
function postVideoToLocket($idToken, $videoUrl, $thumbnailUrl, $caption) {
    $url = "https://api.locketcamera.com/postMomentV2";
    
    $data = [
        "data" => [
            "thumbnail_url" => $thumbnailUrl,
            "video_url" => $videoUrl,
            "md5" => (string)crc32($videoUrl), // Simplified hash
            "recipients" => [],
            "analytics" => [
                "experiments" => [
                    "flag_4" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "43"],
                    "flag_10" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "505"],
                    "flag_23" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "400"],
                    "flag_22" => ["value" => "1203", "@type" => "type.googleapis.com/google.protobuf.Int64Value"],
                    "flag_19" => ["value" => "52", "@type" => "type.googleapis.com/google.protobuf.Int64Value"],
                    "flag_18" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "1203"],
                    "flag_16" => ["value" => "303", "@type" => "type.googleapis.com/google.protobuf.Int64Value"],
                    "flag_15" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "501"],
                    "flag_14" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "500"],
                    "flag_25" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "23"]
                ],
                "amplitude" => [
                    "device_id" => "BF5D1FD7-9E4D-4F8B-AB68-B89ED20398A6",
                    "session_id" => ["value" => "1722437166613", "@type" => "type.googleapis.com/google.protobuf.Int64Value"]
                ],
                "google_analytics" => ["app_instance_id" => "5BDC04DA16FF4B0C9CA14FFB9C502900"],
                "platform" => "ios"
            ],
            "sent_to_all" => true,
            "caption" => $caption,
            "overlays" => [
                [
                    "data" => [
                        "text" => $caption,
                        "text_color" => "#FFFFFFE6",
                        "type" => "standard",
                        "max_lines" => ["@type" => "type.googleapis.com/google.protobuf.Int64Value", "value" => "4"],
                        "background" => ["material_blur" => "ultra_thin", "colors" => []]
                    ],
                    "alt_text" => $caption,
                    "overlay_id" => "caption:standard",
                    "overlay_type" => "caption"
                ]
            ]
        ]
    ];
    
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'content-type: application/json',
        'authorization: Bearer ' . $idToken
    ]);
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    return $httpCode == 200;
}
```

---

## 5. QUY TRÌNH HOÀN CHỈNH

### Upload và Post Image
```php
// 1. Đăng nhập
$loginResult = locketLogin("your_email@example.com", "your_password");
$userId = $loginResult['localId'];
$idToken = $loginResult['idToken'];

// 2. Đọc file ảnh
$imageData = file_get_contents('path/to/image.jpg');

// 3. Upload ảnh lên Firebase Storage
$thumbnailUrl = uploadImageToLocket($userId, $idToken, $imageData);

// 4. Post lên Locket
$success = postImageToLocket($idToken, $thumbnailUrl, "Caption của bạn");

if ($success) {
    echo "Posted successfully!";
}
```

### Upload và Post Video
```php
// 1. Đăng nhập
$loginResult = locketLogin("your_email@example.com", "your_password");
$userId = $loginResult['localId'];
$idToken = $loginResult['idToken'];

// 2. Đọc file video
$videoData = file_get_contents('path/to/video.mp4');

// 3. Tạo thumbnail từ video (bạn cần dùng FFmpeg hoặc thư viện khác)
// Ví dụ đơn giản: dùng ảnh có sẵn
$thumbnailData = file_get_contents('path/to/thumbnail.jpg');

// 4. Upload thumbnail
$thumbnailUrl = uploadImageToLocket($userId, $idToken, $thumbnailData);

// 5. Upload video
$videoUrl = uploadVideoToLocket($userId, $idToken, $videoData);

// 6. Post lên Locket
$success = postVideoToLocket($idToken, $videoUrl, $thumbnailUrl, "Caption của bạn");

if ($success) {
    echo "Video posted successfully!";
}
```

---

## 6. LƯU Ý QUAN TRỌNG

### Giới hạn kích thước
- **Image**: Khuyến nghị < 1MB (theo code gốc)
- **Video**: Khuyến nghị < 10MB (theo code gốc)

### Token hết hạn
- `idToken` từ Firebase có thời gian hết hạn
- Cần xử lý refresh token hoặc login lại khi token hết hạn

### Firebase AppCheck Token
- Token `X-Firebase-AppCheck` trong header login có thể hết hạn
- Token này được hard-code trong source code, có thể cần update định kỳ

### User-Agent
- Nên giữ nguyên User-Agent giống iOS app để tránh bị phát hiện

### API Key
- API Key: `AIzaSyCQngaaXQIfJaH0aS2l7REgIjD7nL431So`
- Firebase Project ID: `locket-4252a`
- GMPID: `1:641029076083:ios:cc8eb46290d69b234fa606`

---

## 7. TROUBLESHOOTING

### Lỗi Authentication
- Kiểm tra email/password
- Kiểm tra idToken còn hạn không
- Kiểm tra X-Firebase-AppCheck token

### Lỗi Upload
- Kiểm tra kích thước file
- Kiểm tra format file (webp cho image, mp4 cho video)
- Kiểm tra headers có đầy đủ không

### Lỗi Post
- Kiểm tra thumbnail_url và video_url có hợp lệ không
- Kiểm tra idToken còn hạn không
- Kiểm tra format JSON của request body

---

## 8. CLASS PHP HOÀN CHỈNH

```php
<?php

class LocketAPI {
    private $userId;
    private $idToken;
    private $apiKey = "AIzaSyCQngaaXQIfJaH0aS2l7REgIjD7nL431So";
    
    public function login($email, $password) {
        $url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key={$this->apiKey}";
        
        $data = json_encode([
            "email" => $email,
            "password" => $password,
            "clientType" => "CLIENT_TYPE_IOS",
            "returnSecureToken" => true
        ]);
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            "Content-Type: application/json",
            "User-Agent: FirebaseAuth.iOS/10.23.1 com.locket.Locket/1.82.0 iPhone/18.0 hw/iPhone12_1",
            "X-Client-Version: iOS/FirebaseSDK/10.23.1/FirebaseCore-iOS",
            "X-Firebase-GMPID: 1:641029076083:ios:cc8eb46290d69b234fa606"
        ]);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        $result = json_decode($response, true);
        
        if (isset($result['localId'])) {
            $this->userId = $result['localId'];
            $this->idToken = $result['idToken'];
            return true;
        }
        
        return false;
    }
    
    public function uploadImage($imageData) {
        if (!$this->userId || !$this->idToken) {
            throw new Exception("Not logged in");
        }
        
        $imageName = time() . "_image.webp";
        $imageSize = strlen($imageData);
        
        // Step 1: Initialize upload
        $url = "https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{$this->userId}%2Fmoments%2Fthumbnails%2F{$imageName}?uploadType=resumable&name=users%2F{$this->userId}%2Fmoments%2Fthumbnails%2F{$imageName}";
        
        $metadata = json_encode([
            "name" => "users/{$this->userId}/moments/thumbnails/{$imageName}",
            "contentType" => "image/*",
            "bucket" => "",
            "metadata" => [
                "creator" => $this->userId,
                "visibility" => "private"
            ]
        ]);
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $metadata);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'content-type: application/json; charset=UTF-8',
            'authorization: Bearer ' . $this->idToken,
            'x-goog-upload-protocol: resumable',
            'x-goog-upload-command: start',
            'x-goog-upload-content-length: ' . $imageSize,
            'x-firebase-storage-version: ios/10.13.0',
            'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)',
            'x-goog-upload-content-type: image/webp',
            'x-firebase-gmpid: 1:641029076083:ios:cc8eb46290d69b234fa609'
        ]);
        
        $response = curl_exec($ch);
        $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $headers = substr($response, 0, $headerSize);
        curl_close($ch);
        
        preg_match('/X-Goog-Upload-URL: (.*)/', $headers, $matches);
        $uploadUrl = trim($matches[1]);
        
        // Step 2: Upload file
        $ch = curl_init($uploadUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
        curl_setopt($ch, CURLOPT_POSTFIELDS, $imageData);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'content-type: application/octet-stream',
            'x-goog-upload-protocol: resumable',
            'x-goog-upload-offset: 0',
            'x-goog-upload-command: upload, finalize',
            'upload-incomplete: ?0',
            'upload-draft-interop-version: 3',
            'user-agent: com.locket.Locket/1.43.1 iPhone/17.3 hw/iPhone15_3 (GTMSUF/1)'
        ]);
        
        curl_exec($ch);
        curl_close($ch);
        
        // Step 3: Get download URL
        $getUrl = "https://firebasestorage.googleapis.com/v0/b/locket-img/o/users%2F{$this->userId}%2Fmoments%2Fthumbnails%2F{$imageName}";
        
        $ch = curl_init($getUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'content-type: application/json; charset=UTF-8',
            'authorization: Bearer ' . $this->idToken
        ]);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        $data = json_decode($response, true);
        $downloadToken = $data['downloadTokens'];
        
        return "{$getUrl}?alt=media&token={$downloadToken}";
    }
    
    public function postImage($thumbnailUrl, $caption) {
        if (!$this->idToken) {
            throw new Exception("Not logged in");
        }
        
        $url = "https://api.locketcamera.com/postMomentV2";
        
        $data = json_encode([
            "data" => [
                "thumbnail_url" => $thumbnailUrl,
                "caption" => $caption,
                "sent_to_all" => true
            ]
        ]);
        
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'content-type: application/json',
            'authorization: Bearer ' . $this->idToken
        ]);
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        return $httpCode == 200;
    }
    
    public function uploadAndPostImage($imagePath, $caption) {
        $imageData = file_get_contents($imagePath);
        $thumbnailUrl = $this->uploadImage($imageData);
        return $this->postImage($thumbnailUrl, $caption);
    }
}

// Sử dụng
$locket = new LocketAPI();

if ($locket->login("your_email@example.com", "your_password")) {
    echo "Login successful!\n";
    
    $success = $locket->uploadAndPostImage("path/to/image.jpg", "My caption");
    
    if ($success) {
        echo "Image posted successfully!";
    } else {
        echo "Failed to post image";
    }
} else {
    echo "Login failed";
}

?>
```

---

**Chúc bạn code thành công!** 🚀
