Related
I'm not an expert in API development or using signed messages in PHP.
I have however tried to get the GATE.IO v4 API working in my PHP implementation but keep getting "Signature mismatch". I have followed the API documentation for CREATE ORDER available at Gate.io's website here: https://www.gate.tv/docs/developers/apiv4/#create-an-order
I have managed to get the /spot/accounts working, so I know that the key and secret are correct.
Based on the code below I seem to missing something. Probably a tiny error but those are the hardest, right?
Does anyone have any idea what could be the cause of this issue? Would really appreciate your help after having spent 8+ hours trying to get this to work.
<?php
$accessToken = ''; // Access token for OAuth/Bearer authentication
$key = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$username = ''; // Username for HTTP basic authentication
$password = ''; // Password for HTTP basic authentication
$host = 'https://api.gateio.ws/api/v4'; // The host
$userAgent = 'OpenAPI-Generator/5.26.0/PHP'; // User agent of the HTTP request, set to "OpenAPI-Generator/{version}/PHP" by default
$sResourcePath = "/spot/orders";
$sMethod = "POST"; // POST or GET
$aPayload['currency_pair'] = "DOT_USDT";
$aPayload['price'] = "6.330033";
$aPayload['account'] = "spot";
$aPayload['side'] = "buy";
$aPayload['amount'] = "1";
$aPayload['time_in_force'] = "gtc";
$sBody = json_encode($aPayload);
$aQueryParams = $aPayload;
$aFullPath = parse_url($host . $sResourcePath);
$fullPath = $aFullPath['path'];
$timestamp = time();
$hashedPayload = hash("sha512", ($payload !== null) ? $payload : "");
$fmt = "%s\n%s\n%s\n%s\n%s";
$sQuery = http_build_query($aQueryParams, false);
$signatureString = sprintf($fmt, $sMethod, $fullPath, $sQuery, $hashedPayload, $timestamp);
$signature = hash_hmac("sha512", $signatureString, $secret);
$aSignHeaders = array(
"KEY" => $key,
"SIGN" => $signature,
"Timestamp" => $timestamp);
$aHeaders[] = "KEY: " . $aSignHeaders['KEY'];
$aHeaders[] = "SIGN: " . $aSignHeaders['SIGN'];
$aHeaders[] = "Timestamp: " . $aSignHeaders['Timestamp'];
$aExtraParams['sHttpHeaders'] = $aHeaders;
if ($sMethod == "POST")
{
$sParams = "?" . http_build_query($aQueryParams, false);
}
else
{
$sQuery = "";
}
$sSubmitUrl = $host . $sResourcePath . $sParams;
$sPage = CURL::doRequest($sMethod, $sSubmitUrl, $sParams, $aExtraParams);
$aPage = json_decode($sPage, true);
if ($aPage)
{
$iPage = count($aPage);
}
echo "<pre>";
print_r($aPage);
echo "</pre>";
?>
based on that example request, you should be doing something like this
//path & urls
$host = 'https://api.gateio.ws';
$prefix = '/api/v4';
$path = '/spot/orders';
$fullPath = "$prefix$path";
$method = 'POST';
//your API keys
$api = [
'secret' => 'xxxx'
];
// Your actual data you can easily modify
$payload = [
'currency_pair' => 'DOT_USDT',
'price' => '6.330033',
'account' => 'spot',
'side' => 'buy',
'amount' => '1',
'time_in_force' => 'gtc'
];
//Convert your data to JSON FORMAT
$jsonPayload = json_encode( $payload );
//Hash your JSON DATA
$hashJsonPayload = hash('sha512', $jsonPayload);
$timeStamp = time();
// dunno if this is required
$queryParam = '';
//Create your signature string
$signString="$method\n$fullPath\n$queryParam\n$hashJsonPayload\n$timeStamp";
//Generate the signature
$signHash = hash_hmac('sha512', $signString, $api['secret']);
// Your Actual headers
$headers = [
'Content-Type: application/json',
'Timestamp: '.$timeStamp,
'Key: '.$api['secret'],
'SIGN: '.$signHash
];
Example request using php curl
$ch = curl_init( "$host$fullPath" ); // URL to POST https://api.gateio.ws/api/v4/spot/orders
curl_setopt( $ch, CURLOPT_POSTFIELDS, $jsonPayload ); // set json payload as body here
curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers ); //define header here
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
curl_close($ch)
echo '<pre>', print_r($result, 1), '</pre>';
I'm trying to create an issue in JIRA from my PHP YII2 framework.
What I'm trying to do is - Whenever I create a new version in my system I want that an issue JIRA will be created automatically for this version.
I've found examples in CURL but so far it's not working.
I don't even get any error message. It creates a new version in my system, but nothing happens in JIRA, looks like it's not even trying to connect to JIRA.
This is my VersionController.php -
<?php
namespace app\controllers;
require_once("Curl.php");
use Yii;
use app\models\Version;
use app\models\VersionSearch;
use app\models\Binfile;
use app\models\VersionStatus;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\swiftmailer\Mailer;
use yii\web\UnauthorizedHttpException;
use linslin\yii2\curl;
use understeam\yii2\httpclient;
use understeam\yii2\jira;
/**
* VersionController implements the CRUD actions for Version model.
*/
class VersionController extends Controller
{
public function behaviors()
{
return [
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'delete' => ['post'],
],
],
'access' => [
'class' => \yii\filters\AccessControl::className(),
'only' => ['index','create','update','view'],
'rules' => [
// allow authenticated users
[
'allow' => true,
'roles' => ['#'],
],
// everything else is denied
],
],
];
}
/**
* Lists all Version models.
* #return mixed
*/
public function actionIndex()
{
if (\Yii::$app->user->can('deleteVersion')) {
$template = '{view} {update} {delete} ';
}
else if((\Yii::$app->user->can('changeStatus')) || (\Yii::$app->user->can('uploadVersion'))){
$template = '{view} {update}';
}
else{$template = '{view}';
}
$searchModel = new VersionSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchModel' => $searchModel,
'dataProvider' => $dataProvider,
'template' => $template,
]);
}
/**
* Displays a single Version model.
* #param integer $id
* #return mixed
*/
public function actionView($id)
{
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
/**
* Creates a new Version model.
* If creation is successful, the browser will be redirected to the 'view' page.
* #return mixed
*/
public function actionCreate()
{
if(!\Yii::$app->user->can('createVersion')){
throw new UnauthorizedHttpException("Access denied: You don't have permission to create a version");
}else{
$model = new Version();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
//$this->actionSend();
$this->actionPostExample();
// $this->actionGetExample();
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
}
/**
* Updates an existing Version model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id
* #return mixed
*/
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
/**
* Deletes an existing Version model.
* If deletion is successful, the browser will be redirected to the 'index' page.
* #param integer $id
* #return mixed
*/
public function actionDelete($id)
{
if(!\Yii::$app->user->can('isAdmin')){
throw new UnauthorizedHttpException("Access denied: Only Admin can perform this action!!!");
}else{
$this->findModel($id)->delete();
return $this->redirect(['index']);
}
}
/**
* Finds the Version model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* #param integer $id
* #return Version the loaded model
* #throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($id)
{
if (($model = Version::findOne($id)) !== null) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
public function actionSend()
{
Yii::$app->mailer->compose()
->setFrom('jenya#ttttt.com')
->setTo('jenya#tttt.com')
->setSubject('Message test')
->setTextBody('Plain text content')
->setHtmlBody('<b>test</b>')
->send();
}
public function actionPostExample()
{
define('JIRA_URL', 'http://jiratest.../');
define('USERNAME', 'jenya');
define('PASSWORD', 'password');
function post_to($resource, $data)
{
$jdata = json_encode($data);
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_POST => 1,
CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,
CURLOPT_USERPWD => USERNAME . ':' . PASSWORD,
CURLOPT_POSTFIELDS => $jdata,
CURLOPT_HTTPHEADER => array('Content-type: application/json'),
CURLOPT_RETURNTRANSFER => true
));
$result = curl_exec($ch);
curl_close($ch);
return json_decode($result);
}
$new_issue = array(
'fields' => array(
'project' => array('key' => 'key'),
'issuetype' => array('name' => 'Version Integration Task'),
'summary' => 'Test via REST',
'components' => 'General',
'customfield_10110' => 'name of value',
'fixVersions' => 'name of version',
'Description' => 'Description of issue goes here.',
//'labels' => array('a','b')
)
);
function create_issue($issue)
{
return post_to('issue', $issue);
}
$result = create_issue($new_issue);
if (property_exists($this, 'errors'))
{
echo "Error(s) creating issue:\n";
var_dump($result);
}
else
{
echo "New issue created at " . JIRA_URL ."/browse/{$result}\n";
}
}
}
Curl.php-
<?php
/**
* Yii2 cURL wrapper
* With RESTful support.
*
* #category Web-yii2
* #package yii2-curl
* #author Nils Gajsek <info#linslin.org>
* #copyright 2013-2015 Nils Gajsek<info#linslin.org>
* #license http://opensource.org/licenses/MIT MIT Public
* #version 1.0.7
* #link http://www.linslin.org
*
*/
namespace linslin\yii2\curl;
use Yii;
use yii\base\Exception;
use yii\helpers\Json;
use yii\web\HttpException;
/**
* cURL class
*/
class Curl
{
// ################################################ class vars // ################################################
/**
* #var string
* Holds response data right after sending a request.
*/
public $response = null;
/**
* #var integer HTTP-Status Code
* This value will hold HTTP-Status Code. False if request was not successful.
*/
public $responseCode = null;
/**
* #var array HTTP-Status Code
* Custom options holder
*/
private $_options = array();
/**
* #var object
* Holds cURL-Handler
*/
private $_curl = null;
/**
* #var array default curl options
* Default curl options
*/
private $_defaultOptions = array(
CURLOPT_USERAGENT => 'Yii2-Curl-Agent',
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 30,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
);
// ############################################### class methods // ##############################################
/**
* Start performing GET-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function get($url, $raw = true)
{
return $this->_httpRequest('GET', $url, $raw);
}
/**
* Start performing HEAD-HTTP-Request
*
* #param string $url
*
* #return mixed response
*/
public function head($url)
{
return $this->_httpRequest('HEAD', $url);
}
/**
* Start performing POST-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function post($url, $raw = true)
{
return $this->_httpRequest('POST', $url, $raw);
}
/**
* Start performing PUT-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function put($url, $raw = true)
{
return $this->_httpRequest('PUT', $url, $raw);
}
/**
* Start performing DELETE-HTTP-Request
*
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded
*
* #return mixed response
*/
public function delete($url, $raw = true)
{
return $this->_httpRequest('DELETE', $url, $raw);
}
/**
* Set curl option
*
* #param string $key
* #param mixed $value
*
* #return $this
*/
public function setOption($key, $value)
{
//set value
if (in_array($key, $this->_defaultOptions) && $key !== CURLOPT_WRITEFUNCTION) {
$this->_defaultOptions[$key] = $value;
} else {
$this->_options[$key] = $value;
}
//return self
return $this;
}
/**
* Unset a single curl option
*
* #param string $key
*
* #return $this
*/
public function unsetOption($key)
{
//reset a single option if its set already
if (isset($this->_options[$key])) {
unset($this->_options[$key]);
}
return $this;
}
/**
* Unset all curl option, excluding default options.
*
* #return $this
*/
public function unsetOptions()
{
//reset all options
if (isset($this->_options)) {
$this->_options = array();
}
return $this;
}
/**
* Total reset of options, responses, etc.
*
* #return $this
*/
public function reset()
{
if ($this->_curl !== null) {
curl_close($this->_curl); //stop curl
}
//reset all options
if (isset($this->_options)) {
$this->_options = array();
}
//reset response & status code
$this->_curl = null;
$this->response = null;
$this->responseCode = null;
return $this;
}
/**
* Return a single option
*
* #param string|integer $key
* #return mixed|boolean
*/
public function getOption($key)
{
//get merged options depends on default and user options
$mergesOptions = $this->getOptions();
//return value or false if key is not set.
return isset($mergesOptions[$key]) ? $mergesOptions[$key] : false;
}
/**
* Return merged curl options and keep keys!
*
* #return array
*/
public function getOptions()
{
return $this->_options + $this->_defaultOptions;
}
/**
* Get curl info according to http://php.net/manual/de/function.curl-getinfo.php
*
* #return mixed
*/
public function getInfo($opt = null)
{
if ($this->_curl !== null && $opt === null) {
return curl_getinfo($this->_curl);
} elseif ($this->_curl !== null && $opt !== null) {
return curl_getinfo($this->_curl, $opt);
} else {
return [];
}
}
/**
* Performs HTTP request
*
* #param string $method
* #param string $url
* #param boolean $raw if response body contains JSON and should be decoded -> helper.
*
* #throws Exception if request failed
*
* #return mixed
*/
private function _httpRequest($method, $url, $raw = false)
{
//set request type and writer function
$this->setOption(CURLOPT_CUSTOMREQUEST, strtoupper($method));
//check if method is head and set no body
if ($method === 'HEAD') {
$this->setOption(CURLOPT_NOBODY, true);
$this->unsetOption(CURLOPT_WRITEFUNCTION);
}
//setup error reporting and profiling
Yii::trace('Start sending cURL-Request: '.$url.'\n', __METHOD__);
Yii::beginProfile($method.' '.$url.'#'.md5(serialize($this->getOption(CURLOPT_POSTFIELDS))), __METHOD__);
/**
* proceed curl
*/
$this->_curl = curl_init($url);
curl_setopt_array($this->_curl, $this->getOptions());
$body = curl_exec($this->_curl);
//check if curl was successful
if ($body === false) {
switch (curl_errno($this->_curl)) {
case 7:
$this->responseCode = 'timeout';
return false;
break;
default:
throw new Exception('curl request failed: ' . curl_error($this->_curl) , curl_errno($this->_curl));
break;
}
}
//retrieve response code
$this->responseCode = curl_getinfo($this->_curl, CURLINFO_HTTP_CODE);
$this->response = $body;
//end yii debug profile
Yii::endProfile($method.' '.$url .'#'.md5(serialize($this->getOption(CURLOPT_POSTFIELDS))), __METHOD__);
//check responseCode and return data/status
if ($this->getOption(CURLOPT_CUSTOMREQUEST) === 'HEAD') {
return true;
} else {
$this->response = $raw ? $this->response : Json::decode($this->response);
return $this->response;
}
}
}
I would really appreciate your help, I don't know what else to try.
Thanks in advance.
There is a bug in VersionController.php / actionPostExample() / post_to. As written I would expect the HTTP post to JIRA to result in an HTTP 404 response.
This line:
CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,
Should be:
CURLOPT_URL => JIRA_URL . '/rest/api/2/' . $resource,
../latest/... is used in the JIRA api docs pages but it is not part of the rest API. .../rest/api/2/... is compatible with JIRA 6 and 7.
I did it.
This is the function that works for me:
function post_to($resource, $data)
{
$jdata = json_encode($data);
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_URL => JIRA_URL . '/rest/api/latest/' . $resource,
CURLOPT_USERPWD => USERNAME . ':' . PASSWORD,
CURLOPT_POSTFIELDS => $jdata,
CURLOPT_HTTPHEADER => array('Content-type: application/json'),
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
//CURLOPT_RETURNTRANSFER => true
));
After that I had to fix several things in JSON which are specific for my project.
For easier debugging you can add this:
error_reporting(E_ALL);
ini_set('display_errors', 1);
To get clear errors.
this is my code, i am trying to post tweet with image, but only text get posted?I really really want to post image as well. I am pulling my hair out for that, HELP!!?
<?php
error_reporting(E_ALL);
require_once('TwitterAPIExchange.php');
//echo 'start';
/** Set access tokens here - see: https://dev.twitter.com/apps/ **/
require_once('connect.php');
$recid=$_GET['recid'];
//echo $recid;
$dsn='mysql:host='.$hostname.';dbname=twitter_db';
try{
$dbh=new PDO($dsn,$username,$password);
$dbh->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
$stmt=$dbh->prepare("SELECT * FROM gr_twitter WHERE recid=:recid");
$stmt->execute(array(
'recid'=>$recid
));
$foundResult=$stmt->fetchAll();
$tweetmsg=$foundResult[0]['tweet'];
$tweetImage=$foundResult[0]['tweetImageName'];
$timestamp=$foundResult[0]['sentTimestamp'];
print_r($foundResult);
$stmt2=$dbh->prepare("UPDATE gr_twitter SET sent=1 WHERE recid=:recid");
$stmt2->execute(array(
'recid'=>$recid
));
}
catch(PDOException $e){}
// Perform a GET request and echo the response **/
/** Note: Set the GET field BEFORE calling buildOauth(); **/
$url = 'https://api.twitter.com/1.1/statuses/update.json';
$requestMethod='POST';
////images is stored in D:\Databases\RC_Data_FMS\images\Files\images\tweetImage folder
$tweetImage='D:\Databases\RC_Data_FMS\images\Files\images\tweetImage/images.jpg';
$postfields = array(
'status' => $tweetmsg,
'media' => "#{$tweetImage}"
);
/** POST fields required by the URL above. See relevant docs as above **/
//print_r($postfields).'<br />';
$twitter = new TwitterAPIExchange($Yh_settings);
$response= $twitter->buildOauth($url, $requestMethod)
->setPostfields($postfields)
->performRequest();
echo "Success, you just tweeted!<br />";
var_dump(json_decode($response));
//////////////////////////////////////////////////////////////////////////
function objectToArray($d)
{
if (is_object($d)) {
// Gets the properties of the given object
// with get_object_vars function
$d = get_object_vars($d);
}
if (is_array($d)) {
/*
* Return array converted to object
* Using __FUNCTION__ (Magic constant)
* for recursive call
*/
// return array_map(__FUNCTION__, $d);
} else {
// Return array
// return $d;
}
}
?>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
I recommend you to use tmhOAuth library if you want to post images that are located in your server.
Here you have an example:
<?php
require_once('./tmhOAuth.php');
$tmhOAuth = new tmhOAuth(array(
'consumer_key' => CONSUMER_KEY,
'consumer_secret' => CONSUMER_SECRET,
'user_token' => OAUTH_TOKEN,
'user_secret' => OAUTH_TOKEN_SECRET
));
$tweetText = 'Your text here';
$imageName = 'picture.png';
$imagePath = dirname(__FILE__) . DIRECTORY_SEPARATOR . $imageName;
$code = $tmhOAuth->request(
'POST',
$tmhOAuth->url('1.1/statuses/update_with_media'),
array(
'media[]' => "#{$imagePath};type=image/png;filename={$imageName}",
'status' => $tweetText
),
true, // use auth
true // multipart
);
?>
Hope this helps!
I have managed to set-up yii-user-management. Thanks to help from here.
However, when I am in profile/fields/admin .
I click on edit field and then change the field from required 'no' to 'yes' in the dropdown, then save, but nothing happens.
I also get :
CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(0) NOT NULL DEFAULT 0' at line 1. The SQL statement executed was: ALTER TABLE profile ADD `` (0) NOT NULL DEFAULT 0
When creating a field.
Let me know if you need some code or files. Any help appreciated.
Here is the profile/models/YumProfileField.php
class YumProfileField extends YumActiveRecord
{
const VISIBLE_HIDDEN=0;
const VISIBLE_ONLY_OWNER=1;
const VISIBLE_REGISTER_USER=2;
const VISIBLE_USER_DECISION=3;
const VISIBLE_PUBLIC=4; // Field is public even if the user decides to hide it
/**
* Returns the static model of the specified AR class.
* #param string $className
* #return YumProfileField
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public function isPublic($user = null) {
if($user == null)
$user = Yii::app()->user->id;
if(!$this->visible)
return false;
if($privacy = YumUser::model()->findByPk($user)->privacy) {
if($privacy->public_profile_fields & pow(2, $this->id))
return true;
}
return false;
}
public function tableName()
{
$this->_tableName = Yum::module('profile')->profileFieldTable;
return $this->_tableName;
}
public function scopes()
{
return array(
'forAll'=>array(
'condition'=>'visible='.self::VISIBLE_PUBLIC,
),
'forUser'=>array(
'condition'=>'visible>='.self::VISIBLE_REGISTER_USER,
),
'forOwner'=>array(
'condition'=>'visible>='.self::VISIBLE_ONLY_OWNER,
),
);
}
public static function itemAlias($type,$code=NULL) {
$_items = array(
'field_type' => array(
'INTEGER' => Yum::t('INTEGER'),
'VARCHAR' => Yum::t( 'VARCHAR'),
'TEXT'=> Yum::t( 'TEXT'),
'DATE'=> Yum::t( 'DATE'),
'DROPDOWNLIST' => Yum::t('DROPDOWNLIST'),
'FLOAT'=> Yum::t('FLOAT'),
'BOOL'=> Yum::t('BOOL'),
'BLOB'=> Yum::t('BLOB'),
'BINARY'=> Yum::t('BINARY'),
'FILE'=> 'FILE',
),
'required' => array(
'0' => Yum::t('No'),
'1' => Yum::t('Yes'),
),
'visible' => array(
self::VISIBLE_USER_DECISION => Yum::t('Let the user choose in privacy settings'),
self::VISIBLE_PUBLIC => Yum::t('For all'),
self::VISIBLE_REGISTER_USER => Yum::t('Registered users'),
self::VISIBLE_ONLY_OWNER => Yum::t('Only owner'),
self::VISIBLE_HIDDEN => Yum::t('Hidden'),
),
);
if (isset($code))
return isset($_items[$type][$code]) ? $_items[$type][$code] : false;
else
return isset($_items[$type]) ? $_items[$type] : false;
}
}
The YumFieldsController:
class YumFieldsController extends YumController
{
const PAGE_SIZE=10;
public function accessRules()
{
return array(
array('allow',
'actions'=>array('index', 'create', 'update', 'view', 'admin','delete'),
'users'=>array(Yii::app()->user->name),
'expression' => 'Yii::app()->user->isAdmin()'
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
public function actionView()
{
$this->layout = Yum::module()->adminLayout;
$this->render('view',array(
'model'=>$this->loadModel('YumProfileField'),
));
}
public function actionCreate() {
$this->layout = Yum::module()->adminLayout;
$model = new YumProfileField;
// add to group?
if(isset($_GET['in_group']))
$model->field_group_id=$_GET['in_group'];
if(isset($_POST['YumProfileField'])) {
$model->attributes = $_POST['YumProfileField'];
$field_type = $model->field_type;
if($field_type == 'DROPDOWNLIST')
$field_type = 'INTEGER';
if($model->validate()) {
$sql = 'ALTER TABLE '.YumProfile::model()->tableName().' ADD `'.$model->varname.'` ';
$sql .= $field_type;
if ($field_type!='TEXT' && $field_type!='DATE')
$sql .= '('.$model->field_size.')';
$sql .= ' NOT NULL ';
if ($model->default)
$sql .= " DEFAULT '".$model->default."'";
else
$sql .= (($field_type =='TEXT' || $model->field_type=='VARCHAR')?" DEFAULT ''":" DEFAULT 0");
$model->dbConnection->createCommand($sql)->execute();
$model->save();
$this->redirect(array('view','id'=>$model->id));
}
}
$this->render('create',array(
'model'=>$model,
));
}
public function actionUpdate()
{
$this->layout = Yum::module()->adminLayout;
$model = $this->loadModel('YumProfileField');
if(isset($_POST['YumProfileField']))
{
$model->attributes=$_POST['YumProfileField'];
// ALTER TABLE `test` CHANGE `profiles` `field` INT( 10 ) NOT NULL
// ALTER TABLE `test` CHANGE `profiles` `description` INT( 1 ) NOT NULL DEFAULT '0'
if($model->save())
$this->redirect(array('view','id'=>$model->id));
}
$this->render('update',array(
'model'=>$model,
));
}
public function actionDelete()
{
$this->layout = Yum::module()->adminLayout;
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$model = $this->loadModel('YumProfileField');
$sql = 'ALTER TABLE '.YumProfile::model()->tableName().' DROP `'.$model->varname.'`';
if ($model->dbConnection->createCommand($sql)->execute()) {
$model->delete();
}
if(!isset($_POST['ajax']))
$this->redirect(array('index'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
public function actionIndex()
{
$this->layout = Yum::module()->adminLayout;
$dataProvider=new CActiveDataProvider('YumProfileField', array(
'pagination'=>array(
'pageSize'=>self::PAGE_SIZE,
),
'sort'=>array(
'defaultOrder'=>'position',
),
));
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
public function actionAdmin()
{
$this->layout = Yum::module()->adminLayout;
$dataProvider=new CActiveDataProvider('YumProfileField', array(
'pagination'=>array(
'pageSize'=>self::PAGE_SIZE,
),
'sort'=>array(
'defaultOrder'=>'position',
),
));
$this->render('admin',array(
'dataProvider'=>$dataProvider,
));
}
}
YumProfile.php model
class YumProfile extends YumActiveRecord
{
const PRIVACY_PRIVATE = 'private';
const PRIVACY_PUBLIC = 'public';
/**
* #var array of YumProfileFields
*/
static $fields=null;
public function init()
{
parent::init();
// load profile fields only once
$this->loadProfileFields();
}
public function afterSave() {
if($this->isNewRecord)
Yii::log(Yum::t( 'A profile been created: {profile}', array(
'{profile}' =>json_encode($this->attributes))));
else
Yii::log(Yum::t( 'A profile been update: {profile}', array(
'{profile}' => json_encode($this->attributes))));
return parent::afterSave();
}
public function recentComments($count = 3) {
$criteria = new CDbCriteria;
$criteria->condition = 'id = ' .$this->id;
$criteria->order = 'createtime DESC';
$criteria->limit = $count;
return YumProfileComment::model()->findAll($criteria);
}
public function beforeValidate() {
if($this->isNewRecord)
$this->timestamp = time();
return parent::beforeValidate();
}
/**
* #param string $className
* #return YumProfile
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
// All fields that the user has activated in his privacy settings will
// be obtained and returned for the use in the profile view
public function getPublicFields() {
if(!Yum::module('profile')->enablePrivacySetting)
return false;
$fields = array();
if($privacy = YumUser::model()
->cache(500)
->with('privacy')
->findByPk($this->user_id)
->privacy->public_profile_fields) {
$i = 1;
foreach(YumProfileField::model()->cache(3600)->findAll() as $field) {
if(
(($i & $privacy)
&& $field->visible != YumProfileField::VISIBLE_HIDDEN)
|| $field->visible == YumProfileField::VISIBLE_PUBLIC)
$fields[] = $field;
$i*=2;
}
}
return $fields;
}
/**
* Returns resolved table name
* #return string
*/
public function tableName()
{
$this->_tableName = Yum::module('profile')->profileTable;
return $this->_tableName;
}
public function rules()
{
$required = array();
$numerical = array();
$rules = array();
$safe = array();
foreach (self::$fields as $field) {
$field_rule = array();
if ($field->required == 1)
array_push($required, $field->varname);
if ($field->field_type == 'int'
|| $field->field_type == 'FLOAT'
|| $field->field_type =='INTEGER'
|| $field->field_type =='BOOLEAN')
array_push($numerical, $field->varname);
if ($field->field_type == 'DROPDOWNLIST')
array_push($safe, $field->varname);
if ($field->field_type == 'VARCHAR' || $field->field_type == 'TEXT') {
$field_rule = array($field->varname,
'length',
'max'=>$field->field_size,
'min' => $field->field_size_min);
if ($field->error_message)
$field_rule['message'] = Yum::t($field->error_message);
array_push($rules,$field_rule);
}
if ($field->match) {
$field_rule = array($field->varname,
'match',
'pattern' => $field->match);
if ($field->error_message)
$field_rule['message'] = Yum::t( $field->error_message);
array_push($rules,$field_rule);
}
if ($field->range) {
// allow using commas and semicolons
$range=explode(';',$field->range);
if(count($range)===1)
$range=explode(',',$field->range);
$field_rule = array($field->varname,'in','range' => $range);
if ($field->error_message)
$field_rule['message'] = Yum::t( $field->error_message);
array_push($rules,$field_rule);
}
if ($field->other_validator) {
$field_rule = array($field->varname,
$field->other_validator);
if ($field->error_message)
$field_rule['message'] = Yum::t( $field->error_message);
array_push($rules, $field_rule);
}
}
array_push($rules,
array(implode(',',$required), 'required'));
array_push($rules,
array(implode(',',$numerical), 'numerical', 'integerOnly'=>true));
array_push($rules,
array(implode(',',$safe), 'safe'));
$rules[] = array('allow_comments, show_friends', 'numerical');
$rules[] = array('email', 'unique');
$rules[] = array('email', 'CEmailValidator');
$rules[] = array('privacy', 'safe');
return $rules;
}
public function relations()
{
$relations = array(
'user' => array(self::BELONGS_TO, 'YumUser', 'user_id'),
'comments' => array(self::HAS_MANY, 'YumProfileComment', 'profile_id'),
);
$fields = Yii::app()->db->cache(3600)->createCommand(
"select * from ".YumProfileField::model()->tableName()." where field_type = 'DROPDOWNLIST'")->queryAll();
foreach($fields as $field) {
$relations[ucfirst($field['varname'])] = array(
self::BELONGS_TO, ucfirst($field['varname']), $field['varname']);
}
return $relations;
}
// Retrieve a list of all users that have commented my profile
// Do not show my own profile visit
public function getProfileCommentators() {
$commentators = array();
foreach($this->comments as $comment)
if($comment->user_id != Yii::app()->user->id)
$commentators[$comment->user_id] = $comment->user;
return $commentators;
}
public function getProfileFields() {
$fields = array();
if(self::$fields)
foreach(self::$fields as $field) {
$varname = $field->varname;
$fields[$varname] = Yum::t($varname);
}
return $fields;
}
public function name() {
return sprintf('%s %s', $this->firstname, $this->lastname);
}
public function attributeLabels()
{
$labels = array(
'id' => Yum::t('Profile ID'),
'user_id' => Yum::t('User ID'),
'privacy' => Yum::t('Privacy'),
'show_friends' => Yum::t('Show friends'),
'allow_comments' => Yum::t('Allow profile comments'),
);
if(self::$fields)
foreach (self::$fields as $field)
$labels[$field->varname] = Yum::t($field->title);
return $labels;
}
/**
* Load profile fields.
* Overwrite this method to get another set of fields
* Makes use of cache so the amount of sql queries per request is reduced
* #since 0.6
* #return array of YumProfileFields or empty array
*/
public function loadProfileFields()
{
if(self::$fields===null)
{
self::$fields=YumProfileField::model()->cache(3600)->findAll();
if(self::$fields==null)
self::$fields=array();
}
return self::$fields;
}
}
looks like you're trying to add a column with no name or type? MySQL ALTER TABLE examples.
Also, check your db user has permissions to ALTER TABLE.
I have a mobile app that uses Rails/MySQL as a backend (just serves JSON, I know we don't need full blown Rails, but this was the simplest solution to get started). My Rails app uses devise for auth. I'd like my users to be able to also access a Phpbb3 forum without having to sign up again. What's the best way to do this? Have the Phpbb3 forum read accounts right from the same MySQL?
Use the email address as a base.
name a file inside includes/ucp called ucp_my_rails_app_connect.php
<?php
/*
* #package My Package
* #author Me
* #license http://opensource.org/licenses/gpl-license.php GNU Public License
* #link my href
* #copyright (c) my copyright
*
* #license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/
/*
* #ignore
*/
if (!defined('IN_PHPBB'))
{
exit;
}
/*
* ucp_myclass
* my rails app connect
* #package my package
*/
class ucp_my_rails_app_connect
{
var $u_action;
function main($id, $mode)
{
global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
/** Do some DB code here for rails or wrap it in a private function*/
$server_url = generate_board_url();
$key_len = 54 - strlen($server_url);
$key_len = max(6, $key_len); // we want at least 6
$key_len = ($config['max_pass_chars']) ? min($key_len, $config['max_pass_chars']) : $key_len; // we want at most $config['max_pass_chars']
$user_actkey = substr(gen_rand_string(10), 0, $key_len);
$new_user_password = gen_rand_string(8);
$data = array(
'username' => utf8_normalize_nfc(/** rails DB username*/),
'steam_id' => request_var('steam_id', ''),
'new_password' => $new_user_password,
'password_confirm' => $new_user_password,
'email' => strtolower(/** rails DB email*/),
'email_confirm' => strtolower(/** rails DB email*/)
);
if($my_rails_exec_func == $some_val) /* make some code so not just anyone can submit stuff to this area*/
{
//Check and initialize some variables if needed
$error = validate_data($data, array(
'username' => array(
array('string', false, $config['min_name_chars'], $config['max_name_chars']),
array('username', '')),
'new_password' => array(
array('string', false, $config['min_pass_chars'], $config['max_pass_chars']),
array('password')),
'password_confirm' => array('string', false, $config['min_pass_chars'], $config['max_pass_chars']),
'email' => array(
array('string', false, 6, 60),
array('email')),
'email_confirm' => array('string', false, 6, 60),
'tz' => array('num', false, -14, 14),
'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'),
));
$error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error);
if (!sizeof($error))
{
// Which group by default?
$group_name = ($coppa) ? 'REGISTERED_COPPA' : 'REGISTERED';
$sql = 'SELECT group_id
FROM ' . GROUPS_TABLE . "
WHERE group_name = '" . $db->sql_escape($group_name) . "'
AND group_type = " . GROUP_SPECIAL;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
$group_id = $row['group_id'];
if (($config['require_activation'] == USER_ACTIVATION_SELF ||
$config['require_activation'] == USER_ACTIVATION_ADMIN) && $config['email_enable'])
{
$user_actkey = gen_rand_string(mt_rand(6, 10));
$user_type = USER_INACTIVE;
$user_inactive_reason = INACTIVE_REGISTER;
$user_inactive_time = time();
}
else
{
$user_type = USER_NORMAL;
$user_actkey = '';
$user_inactive_reason = 0;
$user_inactive_time = 0;
}
$user_row = array(
'username' => $data['username'],
'user_password' => phpbb_hash($data['new_password']),
'user_email' => $data['email'],
'group_id' => (int) $group_id,
'user_timezone' => (float) $data['tz'],
'user_dst' => $is_dst,
'user_lang' => $data['lang'],
'user_type' => $user_type,
'user_actkey' => $user_actkey,
'user_ip' => $user->ip,
'user_regdate' => time(),
'user_inactive_reason' => $user_inactive_reason,
'user_inactive_time' => $user_inactive_time,
);
if ($config['new_member_post_limit'])
{
$user_row['user_new'] = 1;
}
// Register user...
$user_id = user_add($user_row);
// This should not happen, because the required variables are listed above...
if ($user_id === false)
{
trigger_error('NO_USER', E_USER_ERROR);
}
// DB Error
if(!$result)
{
trigger_error('Unable to connect with phpBB database.');
}
// Okay, captcha, your job is done.
if ($config['enable_confirm'] && isset($captcha))
{
$captcha->reset();
}
if ($coppa && $config['email_enable'])
{
$message = $user->lang['ACCOUNT_COPPA'];
$email_template = 'coppa_welcome_inactive_steam';
}
else if ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable'])
{
$message = $user->lang['ACCOUNT_INACTIVE'];
$email_template = 'user_welcome_inactive_steam';
}
else if ($config['require_activation'] == USER_ACTIVATION_ADMIN && $config['email_enable'])
{
$message = $user->lang['ACCOUNT_INACTIVE_ADMIN'];
$email_template = 'admin_welcome_inactive_steam';
}
else
{
$message = $user->lang['ACCOUNT_ADDED'];
$email_template = 'user_welcome_steam';
}
if ($config['email_enable'])
{
include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
$messenger = new messenger(false);
$messenger->template($email_template, $data['lang']);
$messenger->to($data['email'], $data['username']);
$messenger->headers('X-AntiAbuse: Board servername - ' . $config['server_name']);
$messenger->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']);
$messenger->headers('X-AntiAbuse: Username - ' . $user->data['username']);
$messenger->headers('X-AntiAbuse: User IP - ' . $user->ip);
$messenger->assign_vars(array(
'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])),
'USERNAME' => htmlspecialchars_decode($data['username']),
'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey")
);
if ($coppa)
{
$messenger->assign_vars(array(
'FAX_INFO' => $config['coppa_fax'],
'MAIL_INFO' => $config['coppa_mail'],
'EMAIL_ADDRESS' => $data['email'])
);
}
$messenger->send(NOTIFY_EMAIL);
if ($config['require_activation'] == USER_ACTIVATION_ADMIN)
{
// Grab an array of user_id's with a_user permissions ... these users can activate a user
$admin_ary = $auth->acl_get_list(false, 'a_user', false);
$admin_ary = (!empty($admin_ary[0]['a_user'])) ? $admin_ary[0]['a_user'] : array();
// Also include founders
$where_sql = ' WHERE user_type = ' . USER_FOUNDER;
if (sizeof($admin_ary))
{
$where_sql .= ' OR ' . $db->sql_in_set('user_id', $admin_ary);
}
$sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type
FROM ' . USERS_TABLE . ' ' .
$where_sql;
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
$messenger->to($row['user_email'], $row['username']);
$messenger->im($row['user_jabber'], $row['username']);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($data['username']),
'U_USER_DETAILS' => "$server_url/memberlist.$phpEx?mode=viewprofile&u=$user_id",
'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey")
);
$messenger->send($row['user_notify_type']);
}
$db->sql_freeresult($result);
}
}
$message = $message . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '', '');
trigger_error($message);
}
}
}
}
?>
now we add the class to ucp.php
case 'register':
if ($user->data['is_registered'] || isset($_REQUEST['not_agreed']))
{
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
$module->load('ucp', 'register');
$module->display($user->lang['REGISTER']);
break;
case 'my_rails_app_connect':
if ($user->data['is_registered'])
{
redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
$module->load('ucp', 'my_rails_app_connect');
$module->display($user->lang['REGISTER']);
break;
Now we add a login for the rails app
create a file called railsapp.php
<?php define('IN_PHPBB', true);
$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : '../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
// Load include files.
include($phpbb_root_path . 'common.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx);
// Set up a new user session.
$user->session_begin();
$auth->acl($user->data);
$user->setup('ucp');
$my_rails_user_email = some_code_to_get_user_email_from_rails_database; //maybe use a cookie or make the user allow the phpBB script access to the rails DB or make them login into the rails app
$mysql = 'SELECT user_id
FROM ' . USERS_TABLE
. " WHERE user_email='$my_user_rails_email'";
// Execute the query.
$result = $db->sql_query($sql);
// Retrieve the row data.
$row = $db->sql_fetchrow($result);
// Free up the result handle from the query.
$db->sql_freeresult($result);
// Check to see if we found a user_id with the associated Facebook Id.
if ($row) // User is registered already, let's log him in!
{
// Check for user ban.
if($user->check_ban($row['user_id']))
{
trigger_error($user->lang['BAN_TRIGGERED_BY_USER']);
}
// Log user in.
$result = $user->session_create($row['user_id'], 0, 0, 1);
// Alert user if we failed to log them in.
if(!$result)
{
trigger_error($user->lang['LOGIN_FAILURE']);
}
$redirect = $phpbb_root_path . 'index.' . $phpEx;
$message = ($l_success) ? $l_success : $user->lang['LOGIN_REDIRECT'];
$l_redirect = ($admin) ? $user->lang['PROCEED_TO_ACP'] : (($redirect === "{$phpbb_root_path}index.$phpEx" || $redirect === "index.$phpEx") ? $user->lang['RETURN_INDEX'] : $user->lang['RETURN_PAGE']);
// append/replace SID (may change during the session for AOL users)
$redirect = reapply_sid($redirect);
// Special case... the user is effectively banned, but we allow founders to login
if (defined('IN_CHECK_BAN') && $result['user_row']['user_type'] != USER_FOUNDER)
{
return;
}
$redirect = meta_refresh(3, $redirect);
trigger_error($message . '<br /><br />' . sprintf($l_redirect, '', ''));
}
?>
In index_body.html in styles/your_template_name/templates/ add
Connect With Rails
If you need help just drop by MY phpBB mod support forums to discuss further