Dear Stackoverflow users, I am running into a problem. It is as follows: Currently i am programming a management tool for pfsense, which needs to send a multipart form that the server needs to validate and process. It should enable the voucher based acces control on the interface. However, i am getting the error that my headers are already sent. I did not sent them.
my code is as follows:
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;
}
}
This is the code that allows a curl request to be sent to the server. If the page that is returned is the login page, the login info needs to be sent and the original post request needs to be sent again.
the code that follows is the code to insert a zone:
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;
}
}
This code works by first inserting a zone with the name and description and then updating it to set the interface active and enabling the captive portal page to be displayed. However, if i sent the page without the multipart form(it seems to be that this is the issue) then the authentication is not set correctly. It is set, but it does not work. If i then manually change the authentication setting (it is a radio button, if i choose another radio button and then choose my original radio button it suddenly works)
has anyone have a clue about what i am doing wrong? because with the following code i get the result that my headers are already sent:
$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;
i would appreciate all the help i can get. thanks in advance!