Уважаемые пользователи Stackoverflow!
Я сталкиваюсь с проблемой. Это выглядит следующим образом:
В настоящее время я программирую инструмент управления для pfsense, который должен отправить многокомпонентную форму, которую сервер должен проверить и обработать. Это должно включить основанное на ваучере управление доступом на интерфейсе. Однако я получаю сообщение об ошибке, что мои заголовки уже отправлены. Я не отправил их.
мой код выглядит следующим образом:
protected function doCurl($resourceID=null, $post=null)
{
//volledige url
$url = Yii::app()->params->pfsense['host'].$resourceID;
$ch = curl_init();
if($post != null)
{
$post_string = "";
foreach($post as $key=>$value)
{
if($key != 'enctype')
{
$post_string .= $key.'='.$value.'&';
}
else
{
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: multipart/form-data'
));
}
}
rtrim($post_string, '&');
//var_dump($post);
/**/
curl_setopt($ch,CURLOPT_POST, count($post));
curl_setopt($ch,CURLOPT_POSTFIELDS, $post_string);
//var_dump($post_string);
}
else
{
curl_setopt($ch, CURLOPT_HEADER, true);
}
curl_setopt($ch, CURLOPT_URL, $url);
//omdat het certificaat niet klopt zetten we de verificatie uit.
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
//we setten de useragent en de timeout. Useragent omdat sommige websites iets anders voorschotelen per browser.
//timeout voor als er iets gebeurd wat niet moet
curl_setopt($ch,CURLOPT_USERAGENT,Yii::app()->params->pfsense['useragent']);
curl_setopt($ch,CURLOPT_COOKIEJAR, Yii::app()->params->pfsense['cookiepath']);
curl_setopt($ch,CURLOPT_COOKIEFILE, Yii::app()->params->pfsense['cookiepath']);
curl_setopt($ch, CURLOPT_AUTOREFERER, true );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
$result = array( 'header' => '',
'body' => '',
'http_code' => '',
'last_url' => '');
$header_size = curl_getinfo($ch,CURLINFO_HEADER_SIZE);
$result['header'] = substr($response, 0, $header_size);
$result['body'] = substr( $response, $header_size );
$result['http_code'] = curl_getinfo($ch,CURLINFO_HTTP_CODE);
$result['last_url'] = curl_getinfo($ch,CURLINFO_EFFECTIVE_URL);
//curl_close($ch);
return $result;
}
public function curl($resourceID=null, $post=null)
{
$result = $this->doCurl($resourceID, $post);
if(strpos($result['body'], 'Login') == false && $result['http_code'] != 403)
{
//echo $result['body'];
return $result;
}
else
{
$loginpost = array(
'__csrf_magic' => substr($result['body'], strpos($result['body'],'sid:') , 55),
'login' => urlencode('Login'),
'usernamefld' => urlencode(Yii::app()->params->pfsense['pfuser']),
'passwordfld' => urlencode(Yii::app()->params->pfsense['pfpass'])
);
$result = $this->doCurl('',$loginpost);
$result = $this->doCurl($resourceID, $post);
return $result;
}
}
Это код, который позволяет отправлять запрос скручивания на сервер. Если возвращаемая страница является страницей входа в систему, необходимо отправить информацию о входе в систему и повторить исходный запрос на публикацию.
следующий код является кодом для вставки зоны:
public function insertZone($post)
{
$description = $post['description'];
$interface = $post['interfaces'];
$name = $post['name'];
$post=null;
$post['zone'] = $name;
$post['descr'] = $description;
$post['Submit'] = 'Continue';
$result = $this->curl(Yii::app()->params->pfsense['pfpathtoinsertzone']);
$post['__csrf_magic'] = substr($result['body'], strpos($result['body'],'sid:') , 55);
var_dump($post);
$result = $this->curl(Yii::app()->params->pfsense['pfpathtoinsertzone'], $post);
var_dump($result['body']);
//exit;
if(strpos($result['body'], 'The following input errors were detected') == false)
{
$post = null;
$post['enable'] = 'yes';
$post['interfaces'] = $interface;
$post['Submit'] = 'Save';
$post['name'] = $name;
$result = $this->editZone($post);
if($result != false)
{
$post = null;
$post['zone'] = $name;
$post['enable'] = 'yes';
$post['Submit'] = 'Save';
$result = $this->curl(Yii::app()->params->pfsense['pfpathtovoucherroll'].$name);
$post['__csrf_magic'] = substr($result['body'], strpos($result['body'],'sid:') , 55);
$doc = new DOMDocument();
$doc->loadHTML($result['body']);
$doc->preserveWhiteSpace = false;
if($childs = $doc->getElementsByTagName("textarea"))
{
foreach($childs as $child)
{
if($child->nodeType == XML_TEXT_NODE)
{
continue;
}
if(strpos(trim($child->nodeValue),'BEGIN RSA PRIVATE KEY'))
{
$post['privatekey'] = trim($child->nodeValue);
}
elseif(strpos(trim($child->nodeValue),'BEGIN PUBLIC KEY'))
{
$post['publickey'] = trim($child->nodeValue);
}
}
}
$post['charset'] = $doc->getElementById('charset')->attributes->getNamedItem('value')->nodeValue;
$post['rollbits'] = $doc->getElementById('rollbits')->attributes->getNamedItem('value')->nodeValue;
$post['ticketbits'] = $doc->getElementById('ticketbits')->attributes->getNamedItem('value')->nodeValue;
$post['checksumbits'] = $doc->getElementById('checksumbits')->attributes->getNamedItem('value')->nodeValue;
$post['magic'] = $doc->getElementById('magic')->attributes->getNamedItem('value')->nodeValue;
$result = $this->curl(Yii::app()->params->pfsense['pfpathtovoucherroll'].$name, $post);
if($result['http_code'] >= 100 && $result['http_code'] <= 299)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
public function editZone($post)
{
$zone = $post['name'];
$interfaces = $post['interfaces'];
$post = null;
//$post['localauth_priv'] = 'yes';
//$post['radiussrcip_attribute'] = strtolower($interfaces);
if(is_array($interfaces))
{
$post['cinterface[]'] = array_map('strtolower', $interfaces);
}
else
{
$post['cinterface[]'] = strtolower($interfaces);
}
$post['auth_method'] = 'local';
$post['radiussrcip_attribute'] = 'wan';
$post['radiusvendor'] = 'default';
$post['radmac_format'] = 'default';
$post['enable'] = 'yes';
$post['Submit'] = 'Save';
$post["maxprocperip"] = '';
$post["idletimeout"] = '';
$post["timeout"] = '';
$post["freelogins_count"] = '';
$post["freelogins_resettimeout"] = '';
$post["preauthurl"] = '';
$post["redirurl"] = '';
$post["blockedmacsurl"] = '';
$post["bwdefaultdn"] = '';
$post["bwdefaultup"] = '';
$post["radiusip"] = '';
$post["radiusport"] = '';
$post["radiuskey"] = '';
$post["radiusip2"] = '';
$post["radiusport2"] = '';
$post["radiuskey2"] = '';
$post["radiusip3"] = '';
$post["radiusport3"] = '';
$post["radiuskey3"] = '';
$post["radiusip4"] = '';
$post["radiusport4"] = '';
$post["reauthenticateacct"] = '';
$post["radmac_secret"] = '';
$post["radiusvendor"] = 'default';
$post["radiusnasid"] = '';
$post["radmac_format"] = 'default';
$post["httpsname"] = '';
$post['certref'] = '';
$post['enctype'] = true;
$post['zone'] = $zone;
$post['enable'] = 'yes';
$post['Submit'] = 'Save';
$result = $this->curl(Yii::app()->params->pfsense['pfpathtoupdatezone'].$zone);
//echo $result['last_url'];
$post['__csrf_magic'] = substr($result['body'], strpos($result['body'],'sid:') , 55);
//var_dump($post);
$result = $this->curl(Yii::app()->params->pfsense['pfpathtoupdatezone'].$zone, $post);
ini_set('xdebug.var_display_max_depth', -1);
ini_set('xdebug.var_display_max_children', -1);
ini_set('xdebug.var_display_max_data', -1);
var_dump($result['body']);
exit;
if($result['http_code'] >= 100 && $result['http_code'] <= 299)
{
return true;
}
else
{
//var_dump($result);
///exit;
return $result;
}
}
Этот код работает, сначала вставляя зону с именем и описанием, а затем обновляя ее, чтобы активировать интерфейс и включить отображение страницы портала. Однако, если я отправил страницу без многокомпонентной формы (кажется, что это проблема), тогда аутентификация установлена неправильно. Это установлено, но это не работает. Если я затем вручную изменяю настройку аутентификации (это радио-кнопка, если я выбираю другую радио-кнопку, а затем выбираю свою оригинальную радио-кнопку, она внезапно работает)
кто-нибудь знает, что я делаю не так? потому что с помощью следующего кода я получаю результат, что мои заголовки уже отправлены:
$result = $this->curl(Yii::app()->params->pfsense['pfpathtoupdatezone'].$zone, $post);
ini_set('xdebug.var_display_max_depth', -1);
ini_set('xdebug.var_display_max_children', -1);
ini_set('xdebug.var_display_max_data', -1);
var_dump($result['body']);
exit;
Я был бы признателен за любую помощь, которую я могу получить.
заранее спасибо!
Если что-то, что-то вообще, выводится, например, эхо, var_dump, вы получите эту ошибку.
curl устанавливает заголовки application/x-www-form-urlencoded
, Если данные поста отправляются в виде строки.
Если он отправляется как массив, он использует Content-Type: multipart / form-data
Если это не так, добавьте это, чтобы увидеть заголовок запроса:
Сейчас я точно не знаю, как вы это исправили, но у вас могут быть проблемы.
Похоже, ваши данные находятся в массиве, а затем отправлены в виде жалобы по неизвестной причине.
Это должно было остаться в массиве. Этот код выключен.
Остальное будет выполнено для каждого цикла foreach. Наверное, не повредит ничего, это просто ошибка
foreach($post as $key=>$value)
{
if($key != 'enctype')
{
$post_string .= $key.'='.$value.'&';
}
else
{
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data'));
}
}
Должно было:
if($key == 'enctype'){
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data'));
}
else{
foreach($post as $key=>$value){
$post_string .= $key.'='.$value.'&';
}
}
Я думаю, что вы отправили данные в виде строки, или не совсем.
Это большой вопрос: if($key != 'enctype')
Зачем? Это открытый исходный код?
Вышеуказанный цикл будет использоваться только в том случае, если данные поста должны были быть закодированы.
И эта часть:
if($key == 'enctype'){
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data'));
}
Должно быть просто:
if($key == 'enctype'){
$post_string = $post;
}
Таким образом, поскольку данные записи в массиве curl будут автоматически использовать Content-Type: multipart/form-data
Проблема в том, что если она будет отправлена в виде строки, curl будет использовать application/x-www-form-urlencoded
Затем вы должны добавить это после цикла:
$post_string = urlencode($post_string);
Как это:
else{
foreach($post as $key=>$value){
$post_string .= $key.'='.$value.'&';
}
$post_string = urlencode($post_string);
}
Что получил мой запрос на работу:
Оказалось, что в запросе не было необходимости в энциклопедии. Однако было необходимо, чтобы запрос на обновление был отправлен 3-й раз. Не спрашивай меня почему.