PHPCI
PHPCI copied to clipboard
Unserialize error
Hello,
I had evaluated phpci in a vm awhile back. Now we have an instance in production however the first project I add to it results in the following.
Notice: unserialize(): Error at offset 0 of 2 bytes in /path/to/phpci/PHPCI/Model/Project.php line 63
This is a completely fresh install so I'm at a loss.
bump.. Exception: Notice: unserialize(): Error at offset 0 of 2 bytes in /path/to/phpci/PHPCI/Model/Project.php line 62 when i try integrated with GitLab env: fedora, apache,mysql
So this doesn't fix anything however one thing I figured out was that I shouldn't put the .git in my project url as PHPCI adds this. Personally I think that's a bug but whatever at this point...
So I've dug around - there seems to be a number of bugs relating to gitlab integration. First off is the serialization issue this bug reports.
// Handle old-format (serialized) access information first:
if (!empty($info) && substr($info, 0, 1) != '{') {
$data = unserialize($info);
} else {
$data = json_decode($info, true);
}
somehow fails, the first test ends up being true even though $info tends to be "{"buildId": 1}".
However even if I comment all that out and use json_decode because I'm using a new system so know that nothing will have been serialize - there are still issues.
One part of the code appends a .git to the resource, and another expects there to be no .git.
All of the offending code is in commit 0e1fe3ea220c72052259b28b477919873eef23df
From: ProjectService.php
protected function processAccessInformation(Project &$project)
{
$matches = array();
$reference = $project->getReference();
if ($project->getType() == 'gitlab') {
$info = array();
if (preg_match('`^(.*)@(.*):([0-9]+)?/?(.*)/(.*)\.git`', $reference, $matches)) {
$info['user'] = $matches[1];
$info['domain'] = $matches[2];
$info['port'] = $matches[3];
$project->setReference($matches[4] . '/' . $matches[5]);
}
$project->setAccessInformation($info);
}
}
you can see the reference must end in .git. Meaning that when creating a gitlab project the url must be user@url:/owner/repo.git
However GitlabBuild.php has
protected function getCloneUrl()
{
$key = trim($this->getProject()->getSshPrivateKey());
if (!empty($key)) {
$user = $this->getProject()->getAccessInformation("user");
$domain = $this->getProject()->getAccessInformation("domain");
$port = $this->getProject()->getAccessInformation('port');
$url = $user . '@' . $domain . ':';
if (!empty($port)) {
$url .= $port . '/';
}
$url .= $this->getProject()->getReference() . '.git';
return $url;
}
}
You can see it appends a .git, meaning if I setup a project with git@url:owner/project.git, the clone url becomes git@url:owner/project.git.git which will fail to clone.
To compound this there are validation rules for each project type - I haven't looked into why it isn't being called however ProjectController.php has:
protected function getReferenceValidator($values)
{
return function ($val) use ($values) {
$type = $values['type'];
$validators = array(
'hg' => array(
'regex' => '/^(https?):\/\//',
'message' => 'Mercurial repository URL must be start with http:// or https://'
),
'remote' => array(
'regex' => '/^(git|https?):\/\//',
'message' => 'Repository URL must be start with git://, http:// or https://'
),
'gitlab' => array(
'regex' => '`^(.*)@(.*):(.*)/(.*)\.git`',
'message' => 'GitLab Repository name must be in the format "[email protected]:owner/repo.git"'
),
'github' => array(
'regex' => '/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-\.]+$/',
'message' => 'Repository name must be in the format "owner/repo"'
),
'bitbucket' => array(
'regex' => '/^[a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-\.]+$/',
'message' => 'Repository name must be in the format "owner/repo"'
),
);
if (in_array($type, $validators) && !preg_match($validators[$type]['regex'], $val)) {
throw new \Exception($validators[$type]['message']);
} elseif ($type == 'local' && !is_dir($val)) {
throw new \Exception('The path you specified does not exist.');
}
return true;
};
}
which should apply validation to the repository reference value. Either the regexp is wrong or the form isn't being properly validated.
All this to say that there are two issues. The first being a general issue about project deserialization vs json decoding.
The second is specific to gitlab and how the url/repository path should be validated and used internally. Personally I don't think phpci should be modifying the reference at all. Most of the time the .git is optional from a repository point of view.
Thoughts?
This is still an issue because I get the same on a fresh installation when using Gitlab repositories.
Update: It seems the problem occurs only if you install by downloading manually. Installation via composer doesn't have this problem.
@subdee you mean if you install phpci via composer this bug doesn't exist? But if you download a tarball it does have the bug?
Yes, first I followed the instructions given https://www.phptesting.org/wiki/Installing-PHPCI and I had this issue. Then I followed the instructions given https://www.phptesting.org/install-phpci and it worked fine.
The instructions should actually be consistent, but that's a different issue.
I downloaded phpci archive manually, ran composer install and the bug persists.
EDIT: using composer create-project the bug exists anyway.
The issue persist, i also follow the instructions and ran into this issue
Strange, i recreated the project and the issue doesn't persist anymore
This problem occurs even in current versions. I try to connect my GitLab server with 1.6.5 and the current 1.7.0-beta2 The protocol is https and the address ends with .git All I get is
Sorry, there was a problem
Notice: unserialize(): Error at offset 0 of 2 bytes in /var/www/virtual/username/phpci/PHPCI/Model/Project.php line 100
I think the problem could be here:
protected function processAccessInformation(Project &$project)
{
$matches = array();
$reference = $project->getReference();
if ($project->getType() == 'gitlab') {
$info = array();
if (preg_match('`^(.+)@(.+):([0-9]*)\/?(.+)\.git`', $reference, $matches)) {
$info['user'] = $matches[1];
$info['domain'] = $matches[2];
$info['port'] = $matches[3];
$project->setReference($matches[4]);
}
$project->setAccessInformation($info);
}
}
A viable solution from end-user point of view is that you should not use the https url to the repository, but the ssh one. So this: [email protected]:owner/project.git Instead of this: https://gitlab.com/owner/project.git
This because if you use the last one (https://gitlab.com/user/project.git), $info
will be an empty array, that will create a problem in the following function (since $info will be = '[]', returning true to substr($info, 0, 1) != '{'
):
public function getAccessInformation($key = null)
{
$info = $this->data['access_information'];
// Handle old-format (serialized) access information first:
if (!empty($info) && substr($info, 0, 1) != '{') {
$data = unserialize($info);
} else {
$data = json_decode($info, true);
}
if (is_null($key)) {
$rtn = $data;
} elseif (isset($data[$key])) {
$rtn = $data[$key];
} else {
$rtn = null;
}
return $rtn;
}
I hope this will help.