首页 > 解决方案 > PHP - 异步 foreach 循环

问题描述

我有一个分离音乐曲目的网站,但要这样做,用户应该在订阅中购买积分。

我的问题是,例如,当用户从订阅中剩下 2 个学分并上传 3 个曲目时,我的脚本循环遍历这些曲目并看到有有效的学分并立即启动所有这些学分,并将用户可用学分移动到负数.

我需要异步遍历循环,以便每个轨道有机会在通过下一个轨道之前扣除必要的学分,并且它认为它仍然有学分。

下面是我的完整脚本,我添加了一些评论来解释正在发生的事情:

// i first query my db for tracks that are valid and loop through them
$status = 'validated';
$stmt = $conn->prepare("SELECT * FROM demixer.tracks WHERE status=:status");
$stmt->bindParam(':status', $status);
$stmt->execute();
$result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
foreach($stmt->fetchAll() as $row){
    $track_id = $row['id'];
    echo $track_id.' '.$status.'<br>';
    $account_id = $row['account_id'];
    $length = $row['length'];
    $separation_type = $row['separation_type'];
    $separation_algorithm = $row['separation_algorithm'];
    $upload_id = $row['upload_id'];
    $timings = unserialize($row['timings']);
    
    $length_in_minutes = $length/60;
    
    if($separation_type == 'trial' || $separation_type == 'preview'){
        // if the track is a trial i don't have an issue because it doesn't take any credits
    }else{
        $sub_array = [];
        $valid_sub_array = [];
        $now = date("Y-m-d H:i:s");
        
        // i get an array of valid subscriptions
        $stmt = $conn->prepare("SELECT * FROM demixer.subscriptions WHERE account_id=:account_id AND date_expires>:now");
        $stmt->bindParam(':account_id', $account_id);
        $stmt->bindParam(':now', $now);
        $stmt->execute();
        $result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
        foreach($stmt->fetchAll() as $key=>$row){
            $sub_array[$key] = $row;
        }
        //if its empty i don't have an issue
        if(!empty($sub_array)){
            $i = 0;
            foreach($sub_array as $row){
                $subscription_id = $row['id'];
                $no_songs = $row['no_songs'];
                $no_minutes = $row['no_minutes'];
                $date_expires = $row['date_expires'];
                
                //each subscription has credits for X amount of songs (no_songs) and up to Y length in minutes (no_minutes), when a credit from a subscription is used it is added to the 'subscriptions_used' table in my db, this is the part that needs to be done before looping through to the next track otherwise the credits have not been taken away yet
                $stmt = $conn->prepare("SELECT COUNT(*) FROM demixer.subscriptions_used WHERE subscription_id=:subscription_id");
                $stmt->bindParam(':subscription_id', $subscription_id);
                $stmt->execute();
                $result = $stmt->setFetchMode(PDO::FETCH_ASSOC);
                foreach($stmt->fetchAll() as $row){
                    $no_used = $row['COUNT(*)'];
                }
                if($no_songs>$no_used){
                    if($length_in_minutes<$no_minutes){
                        echo 'this subscription has credits<br />';
                        $valid_sub_array[$i]['sub_id'] = $subscription_id;
                        $valid_sub_array[$i]['no_minutes'] = $no_minutes;
                        $valid_sub_array[$i]['date_expires'] = $date_expires;
                        $i++;
                    }else{
                        $message = 'Demixer only supports tracks up to 10 minutes (600 seconds), please try again with a shorter track';
                        $status = 'error';
                        
                        $stmt = $conn->prepare("UPDATE demixer.tracks SET status=:status, message=:message WHERE id=:track_id");
                        $stmt->bindParam(':status', $status);
                        $stmt->bindParam(':message', $message);
                        $stmt->bindParam(':track_id', $track_id);
                        $stmt->execute();
                    }
                }else{
                    $message = 'You need to buy more credits';
                    $status = 'error';
                    
                    $stmt = $conn->prepare("UPDATE demixer.tracks SET status=:status, message=:message WHERE id=:track_id");
                    $stmt->bindParam(':status', $status);
                    $stmt->bindParam(':message', $message);
                    $stmt->bindParam(':track_id', $track_id);
                    $stmt->execute();
                }
            }
        }else{
            $message = 'You need to buy more credits';
            $status = 'error';
            
            $stmt = $conn->prepare("UPDATE demixer.tracks SET status=:status, message=:message WHERE id=:track_id");
            $stmt->bindParam(':status', $status);
            $stmt->bindParam(':message', $message);
            $stmt->bindParam(':track_id', $track_id);
            $stmt->execute();
        }
        
        array_multisort(array_column($valid_sub_array, 'no_minutes'), SORT_ASC, array_column($valid_sub_array, 'date_expires'), SORT_ASC, $valid_sub_array);
        var_dump($valid_sub_array);
        
        if(!empty($valid_sub_array)){
            $subscription_to_use = $valid_sub_array[0]['sub_id'];
            $stmt = $conn->prepare("INSERT INTO demixer.subscriptions_used (track_id, subscription_id) VALUES (:track_id, :subscription_id)");
            $stmt->bindParam(':track_id', $track_id);
            $stmt->bindParam(':subscription_id', $subscription_id);
            $stmt->execute();
            
            echo 'start full<br />';
            
            $data = array(
                'separationAlgorithm' => $separation_algorithm,
                'uploadId' => $upload_id,
                'outputFormats' => array('mp3')
            );
            $payload = json_encode($data);
            
            $request = curl_init($api_url.'separation/start');
            curl_setopt($request, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($request, CURLOPT_POSTFIELDS, $payload);
            curl_setopt($request, CURLOPT_HTTPHEADER, array('Content-Type:application/json','Authorization:'.$token));
            curl_setopt($request, CURLOPT_CUSTOMREQUEST, "PUT");
            
            $response = curl_exec($request);
            $errors = curl_error($request);
            $httpcode = curl_getinfo($request, CURLINFO_HTTP_CODE);
            curl_close($request);
            
            if(!empty($errors)){
                echo $httpcode.' '.$errors;
            }else{
                echo $httpcode.' '.$response;
            }
            echo '<br />';
            
            $decoded_response = (array)json_decode($response);
            $separation_id = $decoded_response['separationId'];
            
            $start_separation = date(DATE_RFC822);
            $timings['start_separation'] = $start_separation;
            $timings = serialize($timings);
            
            $status = 'processing';
            $stmt = $conn->prepare("UPDATE demixer.tracks SET status=:status, separation_id=:separation_id, timings=:timings WHERE id=:track_id");
            $stmt->bindParam(':status', $status);
            $stmt->bindParam(':separation_id', $separation_id);
            $stmt->bindParam(':timings', $timings);
            $stmt->bindParam(':track_id', $track_id);
            $stmt->execute();
        }
    }
}

标签: phpasynchronousforeach

解决方案


推荐阅读