Less of a blog, and more of a utility post - if you have PHP and want to find out what's eating up your Basecamp file-space allocation, this little script might help you.

Insert your API token in the right spot, insert your email in the user agent, and execute from the command line.



function fetch( $uri )
{
    /* Adjust these three variables */

    //  1 - your Basecamp URL
    $basecamp_url   = 'https://yourbasecamp.basecamphq.com/';

    // 2 - get this from your "Account" section
    $username       = 'YOURAPITOKEN';

    // 3 - enter your main account email, or face potential throttling
    $youremail      = 'youremail@youremail.com';


    $password       = 'notused';
    $session        = curl_init();

    curl_setopt($session, CURLOPT_URL, $basecamp_url . $uri );
    curl_setopt($session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
    curl_setopt($session, CURLOPT_HTTPGET, 1);
    curl_setopt($session, CURLOPT_HEADER, false);
    curl_setopt($session, CURLOPT_HTTPHEADER, array('Accept: application/xml', 'Content-Type: application/xml'));
    curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($session, CURLOPT_USERPWD, $username . ":" . $password);
    curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($session, CURLOPT_USERAGENT, "Circlical Account Maintenance ($youremail)" );

    $response = curl_exec($session);
    curl_close($session);

    return $response;
}

function fffsize( $size )
{
    $base   = @log($size) / log(1024);
    $suffix = array("", "k", "M", "G", "T")[@floor($base)];
    return @round( pow(1024, $base - @floor($base)), 2 ) . $suffix;
}

function info( $str )
{
    echo "\033[01;36m" . $str  . " \033[0m\n";
}

$attachment_list    = [];
$projects           = simplexml_load_string( fetch( 'projects.xml' ) );

foreach( $projects as $p )
{

    $project_name   = $p->name;
    $project_id     = $p->id;
    $ncount         = 0;

    info( "Scanning project $project_name..." );

    do{
        $attachments = simplexml_load_string( fetch( "projects/{$project_id}/attachments.xml?n={$ncount}" ) );
        if( count( $attachments->attachment ) )
        {
            foreach( $attachments as $a )
            {
                $attachment_list[] = array(
                    'project'   => (string)$project_name,
                    'file'      => (string)$a->name,
                    'size'      => (string)$a->{'byte-size'},
                );

                $ncount++;
            }
        }
    }
    while( count( $attachments->attachment ) >= 100 );
}

// now sort the darned attachments
usort( $attachment_list, function( $a, $b ){
    return $b['size'] - $a['size'];
});

$mask = "| %-20.20s | %-30.30s | %15.15s |\n";


echo printf( $mask, "Project", "File", "Size" );

foreach( $attachment_list as $a )
{
    echo printf( $mask, $a['project'], $a['file'], fffsize( $a['size'] ) );
}