PHP portersAPIと連携して登録する方法
解決したいこと
PHPで求人webサイトを作成しています。
portersAPIを使用してユーザー登録を行いたいですが、登録途中にエラーが出ます。
原因と解決策を教えていただければと思います
発生している問題・エラー
登録に失敗したので、原因を調べるためにvar_dumpしたところ、403が返ってきました。
// $_SESSION[$session_name]['error'] = "登録に失敗しました。";となります
var_dump($contents);exit(); // string(88) "403"
var_dump($obj);exit(); // array(1) { ["Code"]=> string(3) "403" }
var_dump($result);exit();//false
該当するソースコード
//************************************************
// PORTERS認証用クラス(トークン取得など)
//************************************************
Class portersAuth {
//テスト用
const APP_ID = "アプリケーションID";
const SECRET = "アプリケーションのシークレットキー";
const PARTITION_NO = "xxxx"; //テスト用
function getToken(){
// ** OAuth START **
$oAuthUrl = "https://api-hrbc-jp.porterscloud.com/v1/oauth?app_id=".self::APP_ID."&response_type=code_direct";
// PORTERSのOAuthにアクセスしてcode取得
$xmlObj = simplexml_load_file($oAuthUrl);
$oAuthResponce = json_decode(json_encode($xmlObj), true);
// エラーチェック
$this->checkErr($oAuthResponce, "OAuth");
// 戻り値のcode
$code = $oAuthResponce['Code'];
// ** OAuth END **
// ** Token START **
$tokenUrl = "https://api-hrbc-jp.porterscloud.com/v1/token";
// Tokne取得API送信パラメータ
$data = array(
"app_id" => self::APP_ID, //アプリケーションID。
"secret" => self::SECRET, //アプリケーションのシークレット。
"grant_type" => "oauth_code", //認証フローのタイプ(oauth_code)。
"code" => $code //上記OAuthプロセスで取得したコード。
);
$contentData = http_build_query($data, "", "&");
// ヘッダー設定
$options = array(
'http'=>array(
'method'=>'POST',
'header'=>"Content-Type:application/x-www-form-urlencoded",
'content'=>$contentData
)
);
$context = stream_context_create( $options );
// 送信実行
$contents = file_get_contents(
$tokenUrl
, FALSE
, $context
);
$tokenXml = new SimpleXMLElement($contents); //simplexml_load_fileでXMLデータを読み込む。
$tokenResponce = json_decode(json_encode($tokenXml), true); //json_decode(json_encode())でXMLを配列に変換。
// エラーチェック
$this->checkErr($tokenResponce, "Token");
// トークン取得
$accessToken = $tokenResponce['AccessToken'];
return $accessToken;
// ** Token END **
}
function getPartitionNo($accessToken){
// ※※パーティションは基本的に変更しないのでコメントアウト。$pertitinNoに設定済み※※
$partitionUrl = "https://api-hrbc-jp.porterscloud.com/v1/partition?request_type=1&count=1&start=0";
// ヘッダー設定(token利用)
$options = array(
'http'=>array(
'method'=>'GET',
'header'=>"Content-Type:application/xml; charset=UTF-8\r\n" // Content-Type: XMLデータとして指定。
."X-porters-hrbc-oauth-token:".$accessToken // X-porters-hrbc-oauth-token: 認証トークン。
)
);
$context = stream_context_create( $options );
// 送信実行 (file_get_contentsでHTTP GETリクエストを送信。)
$contents = file_get_contents(
$partitionUrl
, FALSE
, $context
);
$partitionXml = new SimpleXMLElement($contents); // SimpleXMLElementでXMLデータを処理。
$partitionResponce = json_decode(json_encode($partitionXml), true);
// エラーチェック
$this->checkErr($partitionResponce, "Partition");
$pertitionNo = $partitionResponce['Item']['Partition.P_Id']; //結果からパーティション番号を抽出
return $pertitionNo;
}
//. エラーチェック (checkErr) このメソッドは、各APIのレスポンスに対してエラーをチェックします。
function checkErr($arr, $apiName){
if(!is_array($arr)){
echo("API:".$apiName."<br>");
echo("エラーが発生しました。<br>アクセス先・パラメータを確認してください<br>");
exit;
}
if($apiName != "OAuth" && $apiName != "Partition" && array_key_exists('Code', $arr)){
echo("API:".$apiName."<br>");
echo("エラーが発生しました。<br>エラーコード表で確認してください<br>https://hrbcapi.porters.jp/hc/ja/articles/115008171708-Result-Code-List<br>");
echo("System Code:".$arr['Code']."<br>");
exit;
}
if(array_key_exists('Error', $arr) && $arr['Error'] != 0){
echo("API:".$apiName."<br>");
echo("エラーが発生しました。<br>");
echo("Error:".$arr['Error']."<br>");
echo("Message:".$arr['Message']."<br>");
exit;
}
return;
}
}
// ********************************************************
// porters登録関数
// ********************************************************
// 求職者の情報を XML 形式で作成し、Porters API に送信して登録を行う PHP の関数です。
function writeCandidate($data,$set_jobno,$kinmu_area) {
// ---------------------------------------------------------
// 認証
// ---------------------------------------------------------
// PORTERSアクセス用クラス
$clsPortersAuth = new portersAuth();
// 認証用トークン取得
$accessToken = $clsPortersAuth->getToken();
$_sex_flg = common::_sex_flg();
$_kibou_flg = common::_kibou_flg();
$_infotype_flg = common::_infotype_flg();
$P_Owner = 32;
$P_Id = '-1';
// ---------------------------------------------------------
// 1.Candidate - Write Candidate...エンティティを XML で作成。
// ---------------------------------------------------------
// 求職者登録を行い、求職者のIDを採番
$xml_data = '';
$xml_data .= '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
$xml_data .= '<Candidate>';
$xml_data .= '<Item>';
$xml_data .= '<Person.P_Id>' . $P_Id . '</Person.P_Id>';
$xml_data .= '<Person.P_Owner>' . $P_Owner . '</Person.P_Owner>';
$xml_data .= '<Person.P_Name>' . mChgString($data['name1']) . ' ' . mChgString($data['name2']) . '</Person.P_Name>'; //名前(姓と名)を設定。
$wk = mChgString($data['name_kana1'] . ' ' . $data['name_kana2']);
$wk2 = mb_convert_kana($wk, "k");
$xml_data .= '<Person.P_Reading>' . $wk2. '</Person.P_Reading>'; //カタカナの読みを設定。
$zip1 = substr($data["zipcode"], 0, 3);
$zip2 = substr($data["zipcode"], 3);
$zip = sprintf("%03d-%04d",$zip1,$zip2);
$xml_data .= '<Person.P_Zipcode>'.$zip.'</Person.P_Zipcode>'; //(郵便番号)などの基本情報を設定。
$xml_data .= '<Person.P_Prefecture>' . $data['pref'] . '</Person.P_Prefecture>'; //
$xml_data .= '<Person.P_City>' . mChgString($data['adress']) . '</Person.P_City>'; //
$xml_data .= '<Person.P_Street>' . mChgString($data['street']) . '</Person.P_Street>'; //
$xml_data .= '<Person.P_Telephone>' . mChgString($data['tel']) . '</Person.P_Telephone>'; //
$xml_data .= '<Person.P_Mail>' . $data['email'] . '</Person.P_Mail>'; //
//メモ
$memo =""; //希望する求人番号 (set_jobno) や登録希望の種類 (instype) などのメモ
// 希望する求人番号 (set_jobno)
if( $set_jobno !="" ){
$memo = "[JOB NO]".$set_jobno."\n";
}
// 登録希望の種類
$instype = "";
$_instype = common::_form_instype();
if( isset($data["instype"]) ){
if( is_array($data["instype"]) ){
if( count($data["instype"])>0 ){
foreach($data["instype"] as $k1=>$v1){
foreach($_instype as $k2=>$v2){
if( $v1==$k2 ){
if( $instype != "" ){
$instype .= ",";
}
$instype .= $v2;
}
}
}
}
}
}
if( $instype !="" ){
$memo .= "[登録希望の種類]".$instype."\n";
}
//★希望沿線
$_ensen = common::_formensen(); //common::_formensen() で沿線の一覧を取得。
$ensen = "";
if( isset($data["ensen"]) ){
if( is_array($data["ensen"]) ){
if( count($data["ensen"])>0 ){
foreach($data["ensen"] as $k1=>$v1){
foreach($_ensen as $k2=>$v2){
if( $v1==$v2['p_alias'] ){
if( $ensen != "" ){
$ensen .= ",";
}
$ensen .= $v2["p_name"];
}
}
}
}
}
}
if( $ensen !="" ){
$memo .= "[希望の沿線]".$ensen."\n";
}
$xml_data .= '<Person.P_Memo>'.$memo.'</Person.P_Memo>'; //
$xml_data .= '</Item>';
$xml_data .= '</Candidate>';
// $xml_dataおわり
$url = "https://api-hrbc-jp.porterscloud.com/v1/candidate?partition=" . $clsPortersAuth::PARTITION_NO;
$options = array('http' => array(
'method' => 'POST',
'header' => 'Content-Type:application/xml; charset=UTF-8' . "\r\n"
. 'Content-length: ' . strlen($xml_data) . "\r\n"
. 'X-porters-hrbc-oauth-token:' . $accessToken,
'content' => $xml_data
));
$context = stream_context_create($options); //resource(26) of type (stream-context)
$contents = file_get_contents( // file_get_contents を使って POST リクエストを送信。
$url
, FALSE
, $context
);
// APIリクエストの前にデータを確認
log_out('Request XML: ' . $xml_data);
log_out('Access Token: ' . $accessToken);
// レスポンスヘッダーも確認
$http_response_header_str = print_r($http_response_header, true);
log_out('Response Headers: ' . $http_response_header_str);
if ($contents === FALSE) {
$error = error_get_last();
log_out('Error during API call: ' . print_r($error, true));
return false;
}
// レスポンスの詳細なチェック
$response_code = 0;
foreach ($http_response_header as $header) {
if (strpos($header, 'HTTP/') === 0) {
$parts = explode(' ', $header);
$response_code = intval($parts[1]);
break;
}
}
log_out('Response Code: ' . $response_code);
// APIレスポンス内容を確認
$response = json_decode($contents, true);
log_out('API Response: ' . print_r($response, true));
if (isset($response['Error']) && $response['Error'] != 0) {
log_out('API Error: ' . $response['Message']);
return false;
}
$pos = strpos($http_response_header[0], '200'); //API からのレスポンスが 200 OK でない場合、エラーログを記録し、エラー処理 (mErrSend) を行う。
if ($pos === false) { //エラーの場合
// 例外処理
$err_msg = '';
$err_msg = '[FileName]:' . __FILE__ . '[Line]:' . __LINE__ . '[Data]:' . (var_export($data, true) . PHP_EOL);
log_out($err_msg);
mErrSend($err_msg);
} else { //エラーじゃない場合、処理する
$obj = json_decode(json_encode(simplexml_load_string($contents)), true);
// var_dump($obj);exit(); //array(1) { ["Code"]=> string(3) "403" }
if (empty($obj['Code']) && $obj['Item']['Code'] == 0) {
$data['Resume.P_Owner'] = $P_Owner;
$data['Resume.P_Candidate'] = $obj['Item']['Id'];
$data['Resume.P_Gender'] = $data['sex']; //性別
$data['Resume.P_ExpectArea'] = $data['area']; //希望の場所
$data['Resume.U_A186DE5ABE9094B821987B1A0FAFCC'] = $data['name_kana1'].' '.$data['name_kana2']; //カナ
if( $data['birth'] =="" ){
$data['Resume.P_DateOfBirth'] = ""; //生年月日
}else{
$data['Resume.P_DateOfBirth'] = str_replace('-', '/', $data['birth']); //生年月日
}
$data['Resume.U_8C7724F2E21F1CE2D2EB5F9A429528'] = $data['insmode']; //登録モード
//郵便番号 ?
$data['Resume.U_491057B396F015B8F3DC4FCA44A24D'] = $data['zipcode'];
$data['Resume.U_5CE1876496D75761501E22CAA2DB06'] = $data['pref']; //都道府県
$data['Resume.P_CityReference'] = $data['adress']; //市区町村
$data['Resume.P_StreetReference'] = $data['street']; //番地
//最寄り駅
$station ="";
foreach($_ensen as $k=>$v){
if( $v["p_alias"]==$data['m_ensen'] ){
$station .= "".$v["p_name"];
}
}
$station .= " ".$data['station'];
$data['Resume.U_7DA891042ECA7D493A3425751F4AEA'] = $station; //沿線 最寄駅名
$data['Resume.U_7D2DD08E787F33AF37409119CA8CF7'] = $data['ekikara']; //駅から(手段) 名称変換
$data['Resume.U_E071AAF5F69DE35209BA5B859C4DDA'] = $data['syoyoutime']; // 所要時間(分) 数字
// $data['Resume.P_MobileReference'] = $data['tel1'].$data['tel2'].$data['tel3']; // 電話番号
$data['Resume.P_MobileReference'] = $data['tel']; // 電話番号
$data['Resume.P_Mail'] = $data['email']; //メールアドレス
$data['Resume.P_RegisterChannel'] = $data['infodata']; //情報源
$data['Resume.U_4306BC9BD2DA298D90D3A4626B8377'] = "";
//就業希望情報
$data['Resume.U_8AB5D82AABBC48A63BFF927F78532B'] = $data['kind']; //紹介希望
//希望業務名
$workdata = array();
if( $data['jobcategory1'] !="" ){
$workdata[] = $data['jobcategory1'];
}
if( $data['jobcategory2'] !="" ){
$workdata[] = $data['jobcategory2'];
}
if( $data['jobcategory3'] !="" ){
$workdata[] = $data['jobcategory3'];
}
$data['Resume.P_ExpectJobCategory'] = $workdata ; //希望業務名
$data['Resume.P_ExpectCondition'] = $data['expectcondition']; //希望給与
$data['Resume.P_DesiredHourlyRate'] = $data['desiredhourlyrate']; //希望の時給[円] 文字
$data['Resume.U_58CABC7C23AC9DA484F90A2C484BF4'] = $data['free']; //希望休日
$data['Resume.P_ExpectArea'] = $data['area']; //希望勤務地その他
$data['Resume.U_72F2F0BB897EE20BE97F558B5FECF7'] = $data['worktype']; //希望期間
$data['Resume.U_249C06A7B2798935EC31590B5D8118'] = $data['worktime']; //希望就業時間
$data['Resume.U_62BBA993B6C50E3C9151514B7CF6C0'] = $data['workover']; //残業
$data['Resume.U_0B8655796CC968A0FE5072FAC34F90'] = $data['kibou']; //稼働可能日 就業開始可能日
// 学歴
$data['Resume.U_220238CFB049EBC7AE905C65F87A28'] = $data['gakureki']; //学歴 //プルダウン選択 高校卒業/短期大卒業/大学卒業/大学院卒業/専門学校卒業/短大卒業を変換
$data['Resume.U_E182D9B71AE22AD4FF1D0A01DE456F'] = $data['comp']; //卒業
$data['Resume.P_Education'] = $data['gakubu']; //学部名 学歴(詳細)に
$data['Resume.P_ChangeJobsCount'] = $data['company_su']; //就業企業数
$_kind = common::_formkind(); //雇用形態
$_jobcategory =common::_form_job_category_new();
$rireki=array();
$experiencedJobCategory=array();
for($i=0;$i<=3;$i++){
$rireki[$i] .="職歴期間(開始):".$data['shoku'.($i+1).'_start']."\n";
$rireki[$i] .="職歴期間(終了):".$data['shoku'.($i+1).'_end']."\n";
$rireki[$i] .="職歴会社名:".$data['shoku'.($i+1).'_compnay']."\n";
$chk=$data['shoku'.($i+1).'_syokusyu'];
$set="";
foreach($_jobcategory as $k=>$v){
if( $chk == $v["p_alias"] ){
$set= $v["p_name"];
$experiencedJobCategory[] = $chk;
}
}
$rireki[$i] .="職歴 職種:".$set."\n";
$rireki[$i] .="職歴 職務内容:".$data['shoku'.($i+1).'_naiyou']."\n";
$chk=$data['shoku'.($i+1).'_keitai'];
$set="";
foreach($_kind as $k=>$v){
if( $chk == $v["p_alias"] ){
$set= $v["p_name"];
}
}
$rireki[$i] .="職歴 雇用形態:".$set."\n";
}
$data['Resume.U_BD7BE24CBBA17CC929D0E4F3535F97'] = $rireki[0];
$data['Resume.U_B1537A89B5B97D06AA244561D3E349'] = $rireki[1];
$data['Resume.U_7CBFF2B56D7C0C44866E498E80EA65'] = $rireki[2];
// 同じキーがあるとエラーになるので重複を削除
$unique = array_unique($experiencedJobCategory);
$data['Resume.P_ExperiencedJobCategory'] = $unique;
//■
$data['Resume.U_F469D5F0F5C96AD0EB1750D62BE3FF'] = $data['license1'];
$data['Resume.U_B39027F36266688A68654C25E722DF'] = $data['license2'];
$data['Resume.U_2D81251C2B2965EA9DB3C04C710B68'] = $data['license3'];
$data['Resume.U_CFA750A4CCC6532E7F06E962DB068A'] = $data['license4'];
$data['Resume.U_F7C31BEC2497B8B8F0D84EA7718921'] = $data['license_other'];
//スキル
$data['Resume.U_4170473D23B0D8C9F5BFB8CD22493F'] = $data['skill']; //スキル
return _resume_write($data); //成功 // 履歴書データ(Resume)を作成または更新するための処理
} else {
// 例外処理
$err_msg = '';
$err_msg = '[FileName]:' . __FILE__ . '[Line]:' . __LINE__ . '[Data]:' . (var_export($data, true) . PHP_EOL);
log_out($err_msg);
mErrSend($err_msg);
}
}
}
$data = [
'insmode' => 'Option.U_041394',
'instype' =>
array (0 => '1',),
'name1' => '姓',
'name2' => '名',
'name_kana1' => 'セイ',
'name_kana2' => 'メイ',
'email' => 'test@gmail.com',
'tel' => '09000000000',
'birth' => '1992-01-15',
'zip_code' => '8160845',
'pref' => '東京都',
'adress' => '新宿区',
'street' => '1-2-3',
'password' => 'passworddayo',
'ensen' => 'Option.U_040517',
'station' => '天神',
'ekikara' => 'Option.U_039887',
'syoyoutime' => '10',
'infodata' => 'Option.U_000101',
'largecate1' => '1',
'jobcategory1' => 'Option.U_041229',
'largecate2' => '1',
'jobcategory2' => 'Option.U_041228',
'largecate3' => '4',
'jobcategory3' => 'Option.U_041265',
'expectcondition' => '1500',
'desiredhourlyrate' => '230000',
'free' => 'Option.U_040513',
'worktype' => 'Option.U_040190',
'worktime' => 'Option.U_001188',
'workover' => 'Option.U_001010',
'kibou' => '2025-04-01',
'gakureki' => 'Option.U_000087',
'comp' => 'Option.U_000095',
'gakubu' => '法学部',
'shoku1_start' => '2020-04-01',
'shoku1_end' => '2022-03-31',
'shoku1_company' => '株式会社テスト',
'shoku1_syokusyu_dai' => '1',
'shoku1_syokusyu' => 'Option.U_041228',
'shoku1_naiyo' => 'データ入力 電話応対',
'shoku1_keitai' => 'Option.P_FullTime',
'shoku2_start' => '2022-04-04',
'shoku2_end' => '2023-12-28',
'shoku2_company' => '株式会社テスト2',
'shoku2_syokusyu_dai' => '2',
'shoku2_syokusyu' => 'Option.U_041248',
'shoku2_naiyo' => '営業 見積書作成',
'shoku2_keitai' => 'Option.P_Contractor',
'shoku3_start' => '2024-01-08',
'shoku3_end' => '2025-02-19',
'shoku3_company' => '株式会社テスト3',
'shoku3_syokusyu_dai' => '4',
'shoku3_syokusyu' => 'Option.U_041265',
'shoku3_naiyo' => '開発 テスト',
'shoku3_keitai' => 'Option.P_TemporaryStaff',
'license1' => '001',
'license2' => '002',
'license3' => '052',
'license4' => '112',
'license_other' => 'ここに資格が入ります テスと',
'zipcode' => '8160845',
'kind' =>
array (0 => 'Option.P_TemporaryStaff',1 => 'Option.P_FullTime',2 =>'Option.P_Contractor',),
'area' => array (0 => 'Option.U_039306',1 => 'Option.U_039307',),
'area_ta' => array (0 => 'Option.U_040521',1 => 'Option.U_040522',
),
'dataList' =>
array (
'image1' => '7a79c35f7ce0704dec63be82440c8182.pdf',
'hdn_image1' => '250221065703_67b84def72871.pdf',
'image2' => 'xxxxxxxxxxxxx.pdf',
'hdn_image2' => '250221065703_67b84def72a61.pdf',
'image3' => '',
'hdn_image3' => '',
'image4' => '',
'hdn_image4' => '',
'image5' => '',
'hdn_image5' => '',
),
'company_su' => '3',
'skill' =>
array (
0 => 'Option.U_003054',
1 => 'Option.U_003116',
)
];
$result = writeCandidate($data,$set_jobno,'');
テスト環境で行っています。
portersのトークンの取得はできていました。
0