PHP скачать большой музыкальный двоичный файл base64_encode / bas64_decode для IOS - PullRequest
0 голосов
/ 07 сентября 2018

Я пытаюсь выполнить POST с iOS на мой PHP-сервер и заставить PHP-сервер вернуть двоичный файл в мое приложение iOS, используя для передачи base64_encode.

Файл загружается на мое устройство iOS, но AVAsset сообщает мне, что файл не воспроизводится, и я не могу понять, где моя ошибка. Я также уверен, что каждое из названий является действительными файлами .wav и .mp3 на сервере.

соответствующая часть PHP-файла:

    $song_to_download = $_POST['title'];
    ...(check if file exists, open 'rb', etc)

    while (!feof($fp))
    {   
        $block = fread($fp, 57 * 143); // based on php.net base64_encode examples
        $base64 = base64_encode($block);
        print $base64;
    }

соответствующий код iOS:

- (NSUInteger) getFileSizeLocal:(NSString *)path
{
    NSFileManager *fm = [NSFileManager defaultManager];
    NSError *error;
    NSDictionary *dict = [fm attributesOfItemAtPath:path error:&error];
    if (dict == nil)
    {
        NSLog(@"getFileSize - ERROR reading file attributes <%@>", error.localizedDescription);
        return 0;
    }
    return [dict[NSFileSize] unsignedIntegerValue];
}

-(void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
{
    // decode the base64 'location' file and write it to the final file
    NSString *path = location.absoluteString;
    if (path.length < 8) {
        NSLog(@"ERROR - <%@> length is less than 8", path);
        return;
    }
    NSInteger fileStrLen = 7;   // 'file://' length - we keep the first / so its a complete hard path in the filesystem
    NSString *filepath = [path substringWithRange:NSMakeRange(fileStrLen, path.length - fileStrLen)]; // strip off 'file://' portion first

    if ([[NSFileManager defaultManager] fileExistsAtPath:filepath] == NO)
    {
        NSLog(@"ERROR - file does NOT exists at path <%@>", filepath);
        return;
    }

    NSFileHandle *fpi = [NSFileHandle fileHandleForReadingAtPath:filepath];

    NSUInteger len = [self getFileSizeLocal:filepath];
    if (len == 0) {
        NSLog(@"ERROR - filesize is zero");
        return;
    }
    NSFileHandle *fpo = [NSFileHandle fileHandleForWritingAtPath:_largePathAndFileToWrite];
    if (fpo == nil)
    {
        [[NSFileManager defaultManager] createFileAtPath:_largePathAndFileToWrite contents:nil attributes:nil];
        fpo = [NSFileHandle fileHandleForWritingAtPath:_largePathAndFileToWrite];
    }

    // Read tmp input file (filepath), WRITE to final filename (_largePathAndFileToWrite)
    NSData *data = nil;
    NSData *decoded64Data = nil;
    NSString *base64String = nil;
    NSUInteger step_size = 10868; // based on php.net base64_encode examples

    @autoreleasepool
    {
        for (NSUInteger x = 0; x < len; x += step_size)
        {
            data = [fpi readDataOfLength:step_size];
            base64String = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            decoded64Data = [base64String dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

            if (decoded64Data == nil)
            {
                NSLog(@"ERROR - failed to decode data from tmp input file at idx <%ld>", (long)x);
                break;
            }
            [fpo seekToEndOfFile];
            [fpo writeData:decoded64Data];
        }
    }
    [fpo closeFile];
    [fpi closeFile];

    NSURL *fileURL = [NSURL fileURLWithPath:_largePathAndFileToWrite];
    AVAsset *asset = [AVURLAsset URLAssetWithURL:fileURL options:nil];
    if (asset.isPlayable) {
        NSLog(@"GOOD");
    }
    if (asset.isReadable) {
        NSLog(@"READABLE");
    }
    else {
        NSLog(@"Asset is BAD %@", _largePathAndFileToWrite);
    }
}

Мой вывод всегда говорит "Актив плохой"

Размер файла, который я пробую, составляет менее 50 Мбайт, а размер на размер файла на устройстве iOS после файла равен скачать.

Когда я пытался воспроизвести его с AVAudioPlayer, он всегда терпел неудачу:

The operation couldn't be completed.

Любая помощь приветствуется. Я провел несколько часов, пытаясь понять это.

Заранее спасибо!

* * Тысяча двадцать-одиной [решено] * * тысяча двадцать-дв

Я пытался сделать это трудным путем. Оказывается, я могу передать это как двоичный файл без base64 кодирования. Вот окончательное решение для всем, кому это тоже нужно:

PHP сторона: (работает для .mp3 .wav .m4a, другие не пробовали)

<?php

$filepath = "./slist/mysong.mp3";

if (file_exists($filepath)) {
    header('Content-Type: application/octect-stream');
    header('Content-Description: File Transfer');
    header('Content-Length: ' . filesize($filepath));
    ob_clean();
    flush();
    readfile($filepath);
}
?>

код ios:

-(void)URLSession:(NSURLSession *)session downloadTask:(nonnull NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(nonnull NSURL *)location
{
    NSLog(@"downloadTask - didFinishDownloadingToURL <%@>", location.absoluteString);

    // decode the base64 'location' file and write it to the final file
    NSString *path = location.absoluteString;
    if (path.length < 8) {
        NSLog(@"ERROR - <%@> length is less than 8", path);
        return;
    }
    NSInteger fileStrLen = 7;   // 'file://' length - we keep the first / so its a complete hard path in the filesystem
    NSString *filepath = [path substringWithRange:NSMakeRange(fileStrLen, path.length - fileStrLen)]; // strip off 'file://' portion first

    if ([[NSFileManager defaultManager] fileExistsAtPath:filepath] == NO)
    {
        NSLog(@"ERROR - file does NOT exists at path <%@>", filepath);
        return;
    }

    // Just Move it into place
    NSError *error;
    if ([[NSFileManager defaultManager] moveItemAtPath:filepath toPath:_largePathAndFileToWrite error:&error] == NO)
    {
        NSLog(@"ERROR - failed to move file - <%@>", error.localizedDescription);
        return;
    }
}
...