Para subir ficheros a S3 desde las aplicaciones JavaScript lo que hago es generar un formulario firmado en PHP y enviarlo desde JS, de esta forma el fichero viaja directamente del ordenador del usuario a S3.
En muchos casos es interesante aplicar etiquetas de costo a estos ficheros para poder después desglosar el coste. Esto es imprescindible si nuestra aplicación la usan varios clientes y debemos facturar a cada uno el importe generado por el almacenamiento y transferencia de sus ficheros.
Estas etiquetas deben especificarse al crear el formulario y firmarse para que en el cliente JS no se puedan alterar.
Después de pasar varias horas buscando porque no existe ni un solo ejemplo de cómo hacer esto en la documentación de Amazon por fin he encontrado cómo se hace. Hay que pasar un campo en el formulario llamado Tagging con el nombre y el valor de la etiqueta codificando siguiendo un esquema que indican en esta página.
$formInputs = [ 'acl' => 'private', 'Content-Type' => $type, 'key' => "company_{$idCompany}/$s3Filename", 'Tagging' => "<Tagging><TagSet><Tag><Key>empresa</Key><Value>{$companyName}</Value></Tag></TagSet></Tagging>
"]; $options = [ ['bucket' => self::S3_BUCKET], ['acl' => 'private'], ['Content-Type' => $type], ['starts-with', '$key', "company_{$idCompany}/"], ['eq', '$Tagging', "<Tagging><TagSet><Tag><Key>empresa</Key><Value>{$companyName}</Value></Tag></TagSet></Tagging
>"] $expires = '+1 hours'; $postObject = new \Aws\S3\PostObjectV4($s3Client, self::S3_BUCKET, $formInputs, $options, $expires);
Actualización 21 de marzo de 2020: después de tanto sufrimiento con esto resulta que las etiquetas de coste no funcionan a nivel de objeto sino de bucket, así que la única forma de separar gastos por clientes es que cada uno tenga su propio bucket.