dprxj1995 2018-01-06 21:08
浏览 258
已采纳

file_get_contents失败,但POST请求成功

spoiler* convoluted code ahead

Context

main.php has a command-line like input, the file's form action attribute is submit.php. submit.php decides what other file to call, based on the input from main.php. In submit.php I adjust variables $url and $data, based on the input, then call file_get_contents with these parameters.

With post requests that do not have session headers I do not have any problem, but once I needed these and tried sending them, I hit a roadblock:

  • the function file_get_contents itself fails.
  • the request made by the function is completed successfully

Example and Symptoms

I hit submit on main.php to call submit.php with parameters to make a post request for list/access/index.php:

  • Server hangs until timeout
  • On timeout I get the following output.

    Warning: file_get_contents(http://localhost/example/list/access/index.php): failed to open stream: HTTP request failed! in /Users/josetaveras/Sites/example/php_toolbox/toolbox.php on line 83

    Warning: Cannot modify header information - headers already sent by (output started at /Users/josetaveras/Sites/example/php_toolbox/toolbox.php:83) in /Users/josetaveras/Sites/example/list/submit.php on line 373

When I go back to my main.php I know the post request is completed successfully because the request made in list/access/index.php simply sets a session variable. This variable is visible when going back to main.php.

Relevant code

submit.php

$result = post_request($url,$data,$headers);
header(
            'Location: '
            .$root_folder_path
            .'list/?h='
            .$hash
            );}
// after post_request we get back to main.php with simple header redirect

toolbox.php

/*
*   recursive merging 2 arrays
*/
function rec_array_merge($ar1,$ar2){
    foreach($ar2 as $k=>$v){
        if(is_array($v)){
            if(isset($ar1[$k])){
                $ar1[$k] = rec_array_merge($ar1[$k],$v);
            }else{
                $ar1[$k]=$v;
            }
        }else{
            $ar1[$k]=$v;
        }
    }
    return $ar1;
}
function serialize_array($array,$map_symbol,$separator_symbol){
    $returnstr = "";
    foreach($array as $k=>$v){
        $returnstr.=$k.$map_symbol.$v.$separator_symbol;
    }
    return $returnstr;
}
function post_request($url,$data,$headers=NULL){
    $post_content = http_build_query($data);
    $default_headers = Array(
        "Content-type"=>"application/x-www-form-urlencoded"
        ,"Content-Length"=>strlen($post_content)
        );

    if(isset($headers)){
        try{
            $headers = rec_array_merge($default_headers,$headers);
        }
        catch(Exception $e){
            print_r($e);
        }
    }else{
        $headers = $default_headers;
        }
    $serialized = serialize_array($headers,": ","
");
    $options = array(
        'http' => array(
            'header'  => $serialized
            ,'method'  => 'POST'
            ,'content' => $post_content
            ,'timeout' => 1 // for debugging purposes
            )
        );

    $context  = stream_context_create($options);
    $result = file_get_contents($url, false, $context); // line 83 on toolbox.php

    return $result;
}

References

I used How do I send a POST request with PHP? to construct my post_request.

Final thoughts

It is redundant to say that I am not so deft with PHP, and I know and understand that I have bad habits. This leads to a little bit of disorder in the code and many poor choices. My impression is that overall this pattern feels fragile. I'm not trying to reinvent the wheel, but I am pointedly avoiding libraries and packages that facilitate any part of this. I understand that a routing package might help me with all of this. I appreciate any feedback you may have on this question. All criticism is welcome and I will try to answer as soon as I can but I have limited connectivity and access to my computing devices. Having said all of that, thank you for reading up to this point.

  • 写回答

1条回答 默认 最新

  • dongzai3139 2018-07-04 10:49
    关注

    After a few months I finally found the reason why this was happening. The worst aspect of this is that I am familiar with error_reporting(E_ALL) and ini('error_notice',1) but I completely forgot about it. I did learn about var_dump($http_response_header) so there is that. Honestly it was in the documentation and I should have found it sooner. Oh well.

    I quote myself

    With post requests that do not have session headers I do not have any problem, but once I needed these and tried sending them, I hit a roadblock

    I was not familiar exactly with how session mechanics work in general, so i mostly ignored the documentation until I found it a few minutes ago. I refer to session_write_close as what I should have read before diving into sessions (or more specifically, attempting to open multiple sessions in a chain of requests (that I thought of as a single request)):

    session data is locked to prevent concurrent writes only one script may operate on a session at any time

    In my submit.php I open the session to access some variables. I basically forgot to close it before making a new request which itself attempted to modify session data. The fix was to use session_write_close() right before post_request().

    Thank you to all who commented.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 ATAC测序到底用什么peak文件做Diffbind差异分析
  • ¥15 安装ubantu过程中第一个vfat 文件挂载失败
  • ¥20 GZ::CTF如何兼容一些靶机?
  • ¥15 etcd集群部署问题
  • ¥20 谁可以帮我一下问一下各位
  • ¥15 为何重叠加权后love图的SMD与svyCreateTableOne函数绘制基线表的不一致
  • ¥15 QFILHelper怎么恢复全字库,提示进程已完成,只能恢复分区文件
  • ¥150 求 《小魔指》街机游戏机整合模拟软件
  • ¥20 你好,我想问下easyExcel下拉多选,或者复选框可以实现吗
  • ¥20 双非跨考工科哪个专业和方向就业前景好?