Overview

Classes

  • gitCurl
  • Overview
  • Class
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 
<?php
/**
 * <h1>GitCurl Documentation</h1>
 * <h2>GitHub API Helper for PHP 5.3+</h2>
 * <p><b>A PHP class that makes it easy to help you 
 * embed commits, issues and milestones on your website.</b></p>
 * @author      Daniel Retzl
 * @copyright   2018
 * @link        http://gitcurl.yawk.io/
 * @license     https://opensource.org/licenses/MIT
 * 
 *
*/
class gitCurl
{
    /** @var string GitHub username */
    public $username = 'username';
    /** @var string GitHub password */
    public $password = 'password';
    /** @var string User Agent String */
    public $userAgent = '';
    /** @var string Project name that will be displayed in heading */
    public $projectName = "yawk.io";
    /** @var string GitHub project URL */
    public $projectUrl = "https://github.com/YaWK/yawk.io/";
    /** @var string Link to the master zip file on GitHub  */
    public $masterZip = "https://github.com/YaWK/yawk.io/archive/master.zip";
    /** @var string GitHub API Link (your request) */
    public $apiURL = 'https://api.github.com/repos/YaWK/yawk.io/milestones?state=open';
    /** @var string Which state should be loaded on default  */
    public $state = 'closed';
    /** @var bool True, if repository needs authentication */
    public $authentication = true;
    /** @var bool True, if user loads a custom repository */
    public $custom = false;
    /** @var string Holds the cURL handle */
    public $curl = ''; 
    /** @var string API result as json string */
    public $result = '';
    /** @var array API result as array */
    public $data = array();

/**
 * Check if cURL is installed and call init method. If cURL is not installed, abort with error message.
*/
public function isInstalled()
{
    // is cURL currently installed?
    if (!function_exists('curl_init'))
    {   // nope, exit with error msg
        die('Sorry, cURL is not installed... :-/');
    }
    else 
    {   // ok, it is installed - init cURL
        $this->initCurl($this->apiURL);
    }
}

/**
 * Set a user defined repository. Expects a correct API URL.
 * @param string $apiurl the API URL string
 * @return string
*/
public function setRepository($apiURL)
{   // check data integrity
    if (isset($apiURL) && (!empty($apiURL) && (is_string($apiURL))))
    {   // set this repository
        $this->apiURL = $apiURL;
        // ok, return this repository
        return $this->apiURL;
    }
}


/**
 * Init curl get curl handle for this repository. Expects a correct API URL.
 * @param string $apiurl the API URL string
 * @return bool return true if curl_init was successful.
*/
public function initCurl($apiURL)
{
    // set this repository (if empty, default will be used)
    $this->apiURL = $this->setRepository($apiURL);

    // get curl handle
    if ($this->curl = curl_init($this->apiURL))
    {   // ok
        return true;
    }
    else 
    {   // error: curl init failed
        die ('Error: could not get cURL handle - failed to init cURL!');
    }
}

/**
 * Set Curl Options
*/
public function setOpts()
{
    // if no custom userAgent is set
    if (isset($this->userAgent) && (empty($this->userAgent)))
    {   // set current userAgent
        $this->userAgent = $_SERVER['HTTP_USER_AGENT'];
    }

    // check if curl handle is set and not empty
    if (!isset($this->curl) || (empty($this->curl)))
    {   // handle is empty - try to init cURL and get handle
        $this->initCurl($this->apiURL);
    }
    // verify ssl host
    curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false); 
    // verify ssl peer
    curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false);
    // set user agent
    curl_setopt($this->curl, CURLOPT_USERAGENT, $this->userAgent);
    // set curl url (github api url)
    curl_setopt($this->curl, CURLOPT_URL, $this->apiURL);
    // timeout after 30 sec
    curl_setopt($this->curl, CURLOPT_TIMEOUT, 30);
    // return data as string
    curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
    if (isset($this->authentication) && ($this->authentication) == true)
    {
        // set basic authentication method
        curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
        // set username and password
        curl_setopt($this->curl, CURLOPT_USERPWD, "$this->username:$this->password");
    }
}


/**
 * Execute cURL handle
*/
public function exeCurl()
{   // set result after executing cURL handle
    /*
    if($this->result = curl_exec($this->curl) === false)
    {
        die('Error: "' . curl_error($this->curl) . '" - Code: ' . curl_errno($this->curl));
    }
    else 
    {
        return $this->result;
    } 
    */

    if (!$this->result = curl_exec($this->curl))
    {
        die('Error: "' . curl_error($this->curl) . '" - Code: ' . curl_errno($this->curl));
    }
    else 
    {
        return $this->result;
    }
}


/**
 * Close this cURL handle
*/
public function closeCurl()
{   // close handle
    curl_close ($this->curl);
}


/**
 * Convert jSON string into multi-dimensional array
*/
public function json2Array()
{   // store data array from json string
    $this->data = json_decode($this->result, true);
}


/**
 * Basic output of data array
*/
public function output()
{
    // output data
    echo "<div class=\"container-fluid\">";
    echo "<hr>";
    echo "<h1>GitHub Project <a href=\"".$this->projectUrl."\" target=\"_blank\" title=\"visit this project on GitHub [open in new tab]\"><i>".$this->projectName."</i></a><br><small>Development Status Overview</small></h1>";
    echo "<hr>";
    echo "<pre>";
    print_r($this->data);
    echo "</pre>";
    echo "</div>";
}


/**
 * Get Data from GitHub. This method set the repository, execute curl and return data as array.  
 * @param string $apiURL the API URL string
 * @return array return data array
*/
public function getData($apiURL)
{
    // set this repository
    $this->apiURL = $this->setRepository($apiURL);
    // check if cURL is installed
    $this->isInstalled();
    // set cURL options
    $this->setOpts();
    // execute cURL command
    $this->exeCurl();
    // close cURL resource
    $this->closeCurl();
    // convert json result string to array 
    $this->json2Array();
    // check if data array is set
    if (is_array($this->data))
    {   // ok, return data
        return $this->data;
    }
}

// calculate timings (require PHP 5.3.0)
/**
 * Calculate difference between two dates. Expect itemDate as string. Return how many days ago as string.  
 * @param string $itemDate the item date as string
 * @return string return how many days have been gone.
*/
public function daysAgo($itemDate)
{
    // modify itemDate string
    // $itemDate = strstr($itemDate, 'T', true);
    $itemDate = substr($itemDate, 0,10);
    // create new dateTime object from itemDate
    $itemDate = new DateTime(date($itemDate));
    // create new dateTime object for comparison
    $today = new DateTime(date("Y-m-d"));
    // calculate how many days ago this item was posted, compared to now (today)
    $since = $today->diff($itemDate)->format("%a");
    
    // check plural
    if ($since == 1)
    {   // singular if its just one day ago
        return "".$since." day ago";
    }
    else if ($since == 0)
    {   // custom string if its today
        return "today";
    }
    else 
    {   // more than one day ago: use plural 
        return "".$since." Days ago";
    }
}


/**
 * If a commit contains a string like 'issue #123', the hashtag will be converted to a link which leads to this issue on GitHub.
 * @param string $commitMessage The commit message as string
 * @return mixed return false, if no commit msg was set or commit message containing link, or just the commit message if no #int was found.
*/
public function replaceIssueWithLink($commitMessage)
{   // check if commit message is set
    if (!isset($commitMessage) || (empty($commitMessage)))
    {   // if not...
        return false;
    }
    // ok, check if it is a string
    else if (is_string($commitMessage)) 
    {   
        // the string to be changed
        $string = $commitMessage;
        // regex pattern: a leading hashtag, followed by minimum 1 digit
        $pattern = '/#{1}\d{1,}/';
        // replacement string
        $replace = '<a href="https://github.com/issues/$0" target="_blank">$0</a>';

        // check, if pattern match on string and save result
        preg_match($pattern, $string, $result);
        
        // check if regex pattern match and result was set  
        if (isset($result[0]))
        {   
            // cut off hashtag from the left
            $issue = ltrim($result[0], "#");
            // replacement string (change text to link)
            $replace = "<a href=\"".$this->projectUrl."issues/".$issue."\" target=\"_blank\" title=\"open this issue on GitHub [in new tab]\">$0</a>";
            // uppercase first letter
            $string = ucfirst($string);
            // return modified string (with link)
            return preg_replace($pattern, $replace, $string);
        }
        else 
        {   
            // regex pattern does not match
            // return plain commit message string (untouched)
            return ucfirst($commitMessage);
        }
    }
}

/**
 * Draw commits with bootstrap card style  
 * @param array $data Array
 * @return array return data array
*/
public function drawCommits($data)
{   // check if data was sent
    if (isset($data) && (!empty($data) && (is_array($data))))
    {
        // draw commits
        foreach ($data as $item => $property) 
        {
            // first array [0]
            if (is_array($property))
            {
                // replace 'issue #...' with a correct link to GitHub
                $commitMessage = $this->replaceIssueWithLink($property['commit']['message']);
                // draw data: on screen
                echo "<div class=\"card animated fadeIn\">
                        <div class=\"card-block\" style=\"padding:10px;\">";
                echo "<p><small><b>".$this->daysAgo($property['commit']['author']['date'])."</b> by <b>".$property['committer']['login']."</b> (<a href=\"mailto:".$property['commit']['author']['email']."\">".$property['commit']['author']['name']."</a>)</small><hr>"
                     .$commitMessage."<br><i><small><a href=\"".$property['html_url']."\" target=\"_blank\">open commit on GitHub</a></i></small></p>";
                echo "</div>
                    </div><br>";
            }
        }
    }
    else 
    {   // maybe data was set before due a call of setData()
        if (isset($this->data) && (!empty($this->data) && (is_array($this->data))))
        {
            // data is not sent, try to load latest 10 commits
            $this->drawCommits($this->getData("https://api.github.com/repos/".$this->username."/".$this->projectName."/commits?per_page=10"));
        }
        else
        {   // no data here - exit with error
            die ("ERROR: No array sent and this->data is also empty.");
        }
    }
}

/**
 * Draw labels that are used in this element. Expects data array  
 * @param array $data Array containing the data
*/
public function getLabels($data)
{
    foreach ($data['labels'] as $label => $property) 
    {
        echo "<span class=\"badge badge-secondary\" style=\"color:#fff; background-color:#".$property['color']."\">".$property['name']."</span>&nbsp;";
    }
}

/**
 * Check open/closed state and draw appropriate icon.   
 * @param string $state Status of this element (open or closed)
 * @return string html code (icon)
*/
public function getIconFor($state)
{   // check if state is set and not empty
    if (isset($state) && (!empty($state)))
    {   // set this state
        $this->state = $state;
        // check if state is open
        if ($this->state === "open")
        {   // ok, set red icon
            return $icon = "<i class=\"fa fa-unlock text-danger\"></i>&nbsp;";
        }
        else 
        {   // state is closed - set green icon
            return $icon = "<i class=\"fa fa-lock text-success\"></i>&nbsp;";
        }
    }
    else 
    {   // no state to set
        return null;
    }
}

/**
 * Draw Issues with bootstrap card style. Expects data array  
 * @param array $data Array containing the data
*/
public function drawIssues($data)
{
    // check if data was sent
    if (isset($data) && (!empty($data) && (is_array($data))))
    {
        // draw commits
        foreach ($data as $item => $property) 
        {
            // first array [0]
            if (is_array($property))
            {   
                // check if milestone title is set and not empty to avoid php warnings if no milestone is set
                if (isset($property['milestone']['title']) && (empty($property['milestone']['title'])))
                {   // in that case: set empty milestone title
                    $property['milestone']['title'] = '';
                }

                // check if milestone URL is set and is not empty
                if (isset($property['milestone']['html_url']) && (!empty($property['milestone']['html_url'])))
                {
                    // set milestone weblink
                    $milestoneLink = "<a href=\"".$property['milestone']['html_url']."\" target=\"_blank\" title=\"open this Milestone on GitHub [new tab]\">open Milestone on GitHub</a>";
                }
                else 
                {   // no milestone, no link
                    $milestoneLink = '';
                }

                // check state to ensure proper date calculation
                if ($this->state == "open")
                {   // state is open, take creation date
                    $since = $property['created_at'];
                }
                else 
                {   // state is closed, take closed date
                    $since = $property['closed_at'];
                }

                // draw data: on screen
                echo "<div class=\"card animated fadeIn\">
                        <div class=\"card-header\">

                            ".$this->getIconFor($this->state)."
                            <small> <b>".$this->daysAgo($since)." 
                            </b>|<b> <a href=\"".$property['milestone']['html_url']."?closed=1\">Issue #".$property['number']."</a> 
                            </b>|<b> ".$property['milestone']['title']."</b></small>

                        </div>
                        <div class=\"card-body\" style=\"padding:20px; margin-top: -10px;\">";
                echo "".$this->getLabels($property)."<hr>
                        <h4>".$property['title']."</h4>
                        ".$property['body']."
                        <hr>
                        <i><small><a href=\"".$property['html_url']."\" target=\"_blank\">open issue on GitHub</a></i></small>
                        <span class=\"pull-right\"><small><i>".$milestoneLink."</i></small></span>";
                echo "</div>
                    </div><br><br>";
            }
        }
    }
    else 
    {   // maybe data was set before due a call of setData()
        if (isset($this->data) && (!empty($this->data) && (is_array($this->data))))
        {
            // data is not sent, try to load latest 10 commits
            $this->getData("https://api.github.com/repos/".$this->username."/".$this->projectName."/issues?state=closed&per_page=10");
        }
    }
}

/**
 * Basic output of data array (for testing purpose)
 * @param array $data Array containing the data
*/
public function printData($data)
{
    if (isset($data) && (!empty($data) && (is_array($data))))
    {
        $this->data = $data;
        echo "<pre>";
        print_r($this->data);
        echo "</pre>";
    }
    else 
    {
        if (isset($this->data) && (!empty($this->data) && (is_array($this->data))))
        {
            echo "<pre>";
            print_r($this->data);
            echo "</pre>";
        }
        else 
        {
            die ('ERROR: No data was set. In order to use the class properly, please make sure to call gitCurl->getData(\'http://api.github.com.........\') before you try to print or draw any data.');
        }
    }
}
}   // end class gitCurl


/*
$milestones_i = count($data);

echo"<div class=\"row\">
<div class=\"col-md-2\">
<h3><small><i class=\"fa fa-fire\"></i></small> Latest <small>Commits</small></h3>
</div>
<div class=\"col-md-4\">
<h3><small><i class=\"fa fa-trophy\"></i></small> Milestones <small>currently achieved ".$milestones_i." goals</small></h3>";
foreach($data as $item)
{
    if ($item['state'] === "closed")
    {
        $headerState = "Closed";
        $stateClass = "text-success";
        $since = $item['closed_at'];
    }
    else 
        {
            $headerState = "Opened";
            $stateClass = "text-warning"; 
            $since = $item['created_at'];
        }

// calculate timings 
$since = strstr($since, 'T', true); // Ab PHP 5.3.0
$since = new DateTime(date($since));
$today = new DateTime(date("Y-m-d"));

    $closedSince = $today->diff($since)->format("%a");
    if ($closedSince == 1)
    {
        $days = "Day ago";
    }
    else if ($closedSince == 0)
    {
        $closedSince = "";
        $days = "today";
    }
    else 
    { 
        $days = "Days ago"; 
    }
    
    echo "
<div class=\"card text-center\">
  <div class=\"card-header\">
  <span class=\"pull-left small\"><b>$headerState</b> $closedSince $days</span>
  <b><i class=\"fa fa-trophy\"></i> Milestone</b>
  <b class=\"pull-right ".$stateClass."\">".$item['state']."</b>
  
  </div>
  <div class=\"card-block\">
    <h4 class=\"card-title\"><br>".$item['title']."</h4>
    <p class=\"card-text\">".$item['description']."</p>
    <a href=\"".$item['html_url']."\" target=\"_blank\" class=\"btn btn-primary\">Open on GitHub</a><br><br>
  </div>
  <div class=\"card-footer text-muted\">
  <small class=\"pull-left\"><small><b>&nbsp;&nbsp;Issues</b><br>&nbsp;open: <b>".$item['open_issues']."</b><br>closed <b>".$item['closed_issues']."</b></small></small>
  <small class=\"pull-right\"><small>created: ".$item['created_at']."<br>updated: ".$item['updated_at']."</small></small>
  </div>
</div><br><br>";
/*
    foreach($item as $sub)
    {
        if (is_array($sub))
        {
            foreach($sub as $key => $option)
            {
                echo $key, ' => ', $option."<br>";
            }
        }
    }
}
/*
echo "</div>
<div class=\"col-md-4\">
<h3><small><i class=\"fa fa-line-chart\"></i></small> Statistics <small>Overview</small></h3></div>
<div class=\"col-md-2\">
<h3><small><i class=\"fa fa-lightbulb-o\"></i></small> Ideas <small>&amp; Requests</small></h3>
</div>
</div>
</div>";
/*

foreach ($data as $item) {
    # code...
    foreach ($item as $key => $value) {
        # code...
        if (is_array($key))
        {
            foreach ($key as $property => $value) {
                # code...
                echo "array: $property : $value";
            }
        }
        echo $key." : ".$value." <br>";
    }
}
*/

/*
if($result = curl_exec($curl) === false)
{
    die('Error: "' . curl_error($curl) . '" - Code: ' . curl_errno($curl));
}
else 
{
    echo "erfolgreich!<br>$result";
    print_r($result);
}   
echo $status_code;
*/
// $result = curl_exec($curl);
// echo $result;

/** get any webpage with curl ext 
$curl = curl_init('http://yawk.io'); 
curl_setopt($curl, CURLOPT_FAILONERROR, true); 
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); 
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); 
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);   
$result = curl_exec($curl); 
echo $result; 
**/

?>
API documentation generated by ApiGen