I am working on a php and angular 6 based single page application.
The project runs normally except for today when I saw the following error at the console:
Access to XMLHttpRequest at 'http://dev.local/scripts/login.php' from origin 'http://localhost:4200' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:4200, *', but only one is allowed.
By dev.local
I mean, the virtual host created using wampserver for testing purposes.
On login.php, I have the following scripts:
PHP call script:
<?php
require_once('../api.php');
//Getting username and password from Angular
$user = $_POST['username'];
$password = $_POST['password'];
$newApi = new api();
$conn = $newApi->connection();
//var_dump($conn);
$res = $newApi->login($conn, $user, $password);
echo json_encode($res);
?>
At the API:
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
header('Content-Type: application/json');
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS');
header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
error_reporting(E_ALL);
require_once('JWT.php');
include_once('../phpmailer/PHPMailer.php');
include_once('../phpmailer/POP3.php');
include_once('../phpmailer/SMTP.php');
include_once('../phpmailer/Exception.php');
class api {
private $username ="root";
private $password ="root";
private $db="reg_sys";
private $host = "localhost";
public $conn;
public $key = "key123";
public $sessionJwt;
public function connection(){
session_start();
try{
$this->conn = new PDO("mysql:host=$this->host;dbname=$this->db", $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->exec("SET CHARACTER SET utf8");
return $this->conn;
}
catch(PDOException $e){
return $e->getMessage();
}
}
public function login($conn, $user, $password){
try{
$exist = $this->checkIfUserExist($conn, $user);
if($exist['exist'])
{
//Check Password and Generate a token
$checkPassword = "SELECT user_id, user_name, user.role_id, roles.role_type
FROM user
LEFT JOIN roles ON user.role_id = roles.role_id
WHERE
user_name = :user
AND
user_password = :pass
LIMIT 1";
$execCheckPassword = $this->conn->prepare($checkPassword);
$execCheckPassword->bindValue('user', $user);
$execCheckPassword->bindValue('pass', $password);
$execCheckPassword->execute();
$fetchRes = $execCheckPassword->fetch();
$resFound = $execCheckPassword->rowCount();
//Then
if($resFound>0)
{
//Generate a JWT
//Array to generate a JWT from
$arrayJWT =
[
'login_id'=>$fetchRes['user_id'],
'username'=> $fetchRes['user_name'],
'user_role'=>$fetchRes['role_type']
];
$encodedJWT = JWT::encode($arrayJWT, $this->key);
$resArray =
[
'jwt'=> $encodedJWT,
'user_exist'=> 'true',
'user_id'=>$fetchRes['user_id'],
'username'=> $fetchRes['user_name'],
'user_role'=>$fetchRes['role_type']
];
$_SESSION['jwt']=$encodedJWT;
}
else
{
$resArray = ['user_exist'=> 'false', 'errorMsg' => "Incorrect Password!!!"];
//Insert into login_attempt table
$sql = "INSERT INTO login_attempt(login_attempt_date, login_attempt_status, user_id)
VALUES(:date_time, :attempt_status, :user_id)";
$exec = $conn->prepare($sql);
$exec->bindValue(':date_time', $this->currentDateTime);
$exec->bindValue(':attempt_status', 'Active');
$exec->bindValue(':user_id', $exist['user_id']);
$exec->execute();
}
}
else
{
$resArray = ['user_exist'=> 'false', 'errorMsg' => "Username doesn't exist"];
}
return $resArray;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
}
At the angular side:
login(username, password): Observable<any> {
let headerOptions = new HttpHeaders();
//headerOptions.append('Access-Control-Allow-Origin', '*');
//headerOptions.append('Access-Control-Request-Headers', '*');
headerOptions.append('Access-Control-Allow-Credentials', 'true');
headerOptions.append('Content-Type', 'application/json');
headerOptions.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
headerOptions.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
this.credentials = { user: username, pass: password };
const httpParams = new HttpParams()
.set('username', username)
.set('password', password);
return this.http.post(this.globalVar.login, httpParams, {
headers: headerOptions,
})
}
As you see, I commented the following:
//headerOptions.append('Access-Control-Allow-Origin', '*');
//headerOptions.append('Access-Control-Request-Headers', '*');
At the httpd-vhosts.conf:
# Virtual Hosts
#
<VirtualHost *:80>
ServerName localhost
ServerAlias localhost
DocumentRoot "${INSTALL_DIR}/www"
<Directory "${INSTALL_DIR}/www/">
Options +Indexes +Includes +FollowSymLinks +MultiViews
Header set Access-Control-Allow-Origin "*"
AllowOverride All
Require local
Allow from 127.0.0.1
Allow from 192.168.10.0
Allow from 192.168.0.217
Require all granted
</Directory>
</VirtualHost>
#dev.local
<VirtualHost *:80>
ServerAdmin it@m.org
DocumentRoot "c:/wamp64/www/dev"
ServerName dev.local
ServerAlias www.dev.local
<Directory "c:/wamp64/www/dev/">
AllowOverride All
Require local
Allow from 127.0.0.1
#Allow from 192.168.10.0
#Allow from 192.168.0.140
Require ip 192.168.0
Require ip 192.168.1
Require ip 192.168.10
Require all granted
Allow from all
</Directory>
</VirtualHost>
And I enabled the mod_headers in httpd.conf
.
I tried the solution from this question on stack, and this answer too, but nothing changed, and still getting the same error.
XHRResponse:
fetch("http://dev.local/scripts/login.php", {"credentials":"omit","headers":{"accept":"application/json, text/plain, /","content-type":"application/x-www-form-urlencoded;charset=UTF-8"},"referrer":"http://localhost:4200/login","referrerPolicy":"no-referrer-when-downgrade","body":"username=test&password=test1","method":"POST","mode":"cors"});